Pessimistic locking is used
Why it matters
For multi-step flows with meaningful capacity constraints, optimistic locking (version fields) surfaces conflicts only at the final commit — after the user has filled the booking form and possibly entered payment details. CWE-362 (race condition) describes the hazard: concurrent requests succeed their availability checks, race to commit, and one fails at the very last step. Pessimistic locking with FOR UPDATE queues concurrent requests sequentially, so each one sees the committed state of the previous one and the user receives immediate feedback before investing time in the flow.
Severity rationale
Low because UNIQUE constraints provide the primary double-booking defense; pessimistic locking reduces late-stage UX failures but is not the sole concurrency control.
Remediation
Acquire a row-level lock on the slot before inserting, inside a transaction. Apply this in your booking service (e.g., src/lib/booking-service.ts).
-- Raw SQL inside a transaction
BEGIN;
SELECT id, booked_count, max_capacity
FROM slots
WHERE id = $1
FOR UPDATE; -- locks the row for this transaction
-- check capacity, insert booking
COMMIT;
With Prisma, use $queryRaw with FOR UPDATE inside a $transaction callback.
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-362 — Concurrent Execution Using Shared Resource with Improper Synchronization
- iso-25010:2011 · reliability.fault-tolerance — Fault Tolerance — pessimistic row locking serializes concurrent booking attempts
Taxons
History
- 2026-04-18·v1.0.0·Initial import from booking-flow-lifecycle·automated