Availability re-checked before commit
Why it matters
In flows where availability is checked when the user loads the booking form and the final insert happens minutes later at payment time, the check and the commit are separated by an unbounded time window. CWE-367 (TOCTOU race condition) names this exact pattern: the condition checked and the action taken are not atomic. A second user who books the same slot during the payment flow will not be detected until the UNIQUE constraint fires — and by then the first user has already been charged or committed their card details. Re-checking inside the transaction collapses the window to zero.
Severity rationale
High because the TOCTOU window between initial check and final insert is exploitable under normal concurrent usage, not just adversarial load.
Remediation
Move the availability query inside the same transaction block as the insert, in your booking creation handler (e.g., src/app/api/bookings/route.ts or src/lib/booking-service.ts).
await db.$transaction(async (tx) => {
// recheck — inside the transaction, atomic with the insert
const conflict = await tx.booking.findFirst({
where: { slotId, startTime, status: { not: 'CANCELLED' } }
});
if (conflict) throw new ConflictError('Slot taken');
await tx.booking.create({ data: { slotId, startTime, ...rest } });
});
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-367 — Time-of-check Time-of-use (TOCTOU) Race Condition
- cwe · CWE-362 — Concurrent Execution Using Shared Resource with Improper Synchronization
- iso-25010:2011 · functional-suitability.functional-correctness
Taxons
History
- 2026-04-18·v1.0.0·Initial import from booking-flow-lifecycle·automated