Retry mechanism is safe
Why it matters
Network timeouts during payment API calls are a normal operational event, and every retry without an idempotency key is a potential double charge. CWE-605 (multiple binds to the same port) and CWE-841 both describe re-entrancy hazards; in payment systems the re-entrancy produces a duplicate charge that Stripe will honor because each request without an idempotency key is treated as a new, independent charge. A customer who retries a failed payment page reload can be charged multiple times. Idempotency keys that are random UUIDs regenerated on each retry defeat the purpose — the key must be deterministically derived from the booking ID so retries produce the same result.
Severity rationale
Low because double-charge risk requires a specific failure mode (network timeout + retry) but the consequence — a customer charged twice — demands immediate manual remediation.
Remediation
Pass a deterministic idempotency key tied to the booking ID in every payment API call. Implement this in src/lib/payment-service.ts or your checkout handler.
const paymentIntent = await stripe.paymentIntents.create(
{
amount,
currency: 'usd',
metadata: { bookingId: booking.id },
},
{
idempotencyKey: `booking-${booking.id}`, // deterministic — same key on retry
}
);
Also add a processed-event check in your webhook handler to guard against Stripe replaying events.
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the Booking Flow & Lifecycle Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- cwe · CWE-605 — Multiple Binds to the Same Port
- cwe · CWE-841 — Improper Enforcement of Behavioral Workflow
- iso-25010:2011 · reliability.fault-tolerance — Fault Tolerance — deterministic idempotency keys prevent double-charge on payment retry
Taxons
History
- 2026-04-18·v1.0.0·Initial import from booking-flow-lifecycle·automated