You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Stripe delivery failure after payment leaves no charge-preserving retry path
#743
Stripe confirms the PaymentIntent before the application handler runs. If the handler fails or its response is lost, payment may succeed without resource delivery.
Replaying the credential returns the original PaymentIntent with an idempotent-replayed marker, which mppx rejects with 402. A fresh SPT uses a new idempotency key and may create another PaymentIntent, leaving no retry path that preserves the original charge.
Impact
A payer can have a succeeded Stripe payment without receiving the protected resource. The original credential cannot recover delivery, while retrying through a fresh challenge and SPT may require another payment. Stripe does not charge the same idempotency key twice; the risk arises when recovery moves to a new key.
Steps to reproduce
Use the mock Stripe client and replay test setup at src/stripe/server/Charge.test.ts:20-37 and src/stripe/server/Charge.test.ts:532-558.
Submit the credential. The PaymentIntent succeeds at src/stripe/server/Charge.ts:139-169; make the downstream handler at src/middlewares/hono.ts:68 fail or discard its response.
Replay the credential. The same idempotency key is used and Stripe reports the replay at src/stripe/server/Charge.ts:291-302.
Observe that mppx rejects it at src/stripe/server/Charge.ts:157-158 and returns 402 at src/server/Mppx.ts:1345-1363, as asserted at src/stripe/server/Charge.test.ts:568-574.
Follow the 402 with a fresh SPT through src/stripe/client/Charge.ts:50-94. Because the SPT is part of the idempotency key at src/stripe/server/Charge.ts:293, this permits a new PaymentIntent attempt.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Description
Stripe confirms the PaymentIntent before the application handler runs. If the handler fails or its response is lost, payment may succeed without resource delivery.
Replaying the credential returns the original PaymentIntent with an
idempotent-replayedmarker, which mppx rejects with 402. A fresh SPT uses a new idempotency key and may create another PaymentIntent, leaving no retry path that preserves the original charge.Impact
A payer can have a succeeded Stripe payment without receiving the protected resource. The original credential cannot recover delivery, while retrying through a fresh challenge and SPT may require another payment. Stripe does not charge the same idempotency key twice; the risk arises when recovery moves to a new key.
Steps to reproduce
src/stripe/server/Charge.test.ts:20-37andsrc/stripe/server/Charge.test.ts:532-558.src/stripe/server/Charge.ts:139-169; make the downstream handler atsrc/middlewares/hono.ts:68fail or discard its response.src/stripe/server/Charge.ts:291-302.src/stripe/server/Charge.ts:157-158and returns 402 atsrc/server/Mppx.ts:1345-1363, as asserted atsrc/stripe/server/Charge.test.ts:568-574.src/stripe/client/Charge.ts:50-94. Because the SPT is part of the idempotency key atsrc/stripe/server/Charge.ts:293, this permits a new PaymentIntent attempt.All reactions