Skip to content

fix(core): harden checkout and Stripe webhook payment integrity - #34

Merged
cavewebs merged 4 commits into
mainfrom
security/payment-integrity-2026-10-05
Oct 5, 2026
Merged

cavewebs merged 4 commits into
mainfrom
security/payment-integrity-2026-10-05

Conversation

@cavewebs

@cavewebs cavewebs commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Harden checkout and Stripe webhook payment integrity so cart totals and paid amounts stay consistent through checkout.

Changes

  • Verify product/variant ownership when pricing cart lines
  • Re-resolve coupon and shipping amounts at checkout (do not trust stale stored amounts)
  • Require paid payment status before marking orders paid (including async payment success)
  • Reconcile PaymentIntent amounts against order totals
  • Fix hosted Checkout Session tax/discount line items

Test plan

  • bun test focused suites (payment-integrity, coupons, cart-calculate, shipping-zones) — 42 pass
  • CI green on this PR
  • Stripe test-mode: one embedded + one hosted purchase
  • Merge, then ship patch via Version Packages (@dashcommerce/core 0.2.1)

Release

Includes a patch changeset for @dashcommerce/core. After merge, Version Packages PR #27 should pick this up for npm publish.

Quiet PR — no public vulnerability detail.

- Enforce variant ownership on add-to-cart and checkout reprice; price lines with the validated variant.
- Re-validate/re-resolve applied coupons on line changes and at checkout; re-quote shipping at checkout and 409 when totals drift.
- Create hosted Checkout orders only when payment_status is paid; handle async_payment_succeeded.
- Require PaymentIntent succeeded; reconcile amount_received vs cart total (on-hold + withhold download grants on mismatch).
- Hosted sessions: send flat/table tax as a line item and apply merchant discounts via a one-time Stripe Coupon.
EmDash 0.37 guards request.text() after parsing into ctx.input.
Cloning preserves the raw payload for signature verification.
Also gitignore .secrets/ for local Stripe key files.
EmDash's product_variants sku uniqueIndex is a table-wide expression on
_plugin_storage, so blank (and repeated catalog) sku values on order_items
collided on the second paid order. Persist catalog SKUs as productSku and
treat checkout.session.completed errors as idempotent when the PI order
already exists.
@cavewebs
cavewebs merged commit 5decf31 into main Oct 5, 2026
2 checks passed
@github-actions github-actions Bot mentioned this pull request Oct 5, 2026
cavewebs added a commit that referenced this pull request Oct 5, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @dashcommerce/core@0.2.1

### Patch Changes

- [#34](#34)
[`55ca9fa`](55ca9fa)
Thanks [@cavewebs](https://github.com/cavewebs)! - Harden checkout and
Stripe webhook payment integrity: verify variant ownership, re-resolve
coupon/shipping amounts at checkout, require paid payment status (incl.
async success), and reconcile PaymentIntent amounts; fix hosted Checkout
Session tax/discount line items.

- [#26](#26)
[`bcdad21`](bcdad21)
Thanks [@cavewebs](https://github.com/cavewebs)! -
Railway/reverse-proxy: use configured public site URL for Stripe
success/cancel and portal return URLs instead of request.origin which
can be localhost:PORT
## @dashcommerce/starter@0.3.2

### Patch Changes

- Updated dependencies
[[`55ca9fa`](55ca9fa),
[`bcdad21`](bcdad21)]:
  - @dashcommerce/core@0.2.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant