# Concurrent requests are handled safely

- **Pattern:** `ab-000543` (`booking-flow-lifecycle.double-booking.concurrent-request-handling`)
- **Severity:** critical
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000543
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000543)

## Why it matters

Application-level availability checks followed by unguarded inserts are the leading cause of double bookings in production systems. Under concurrent load, two requests can both read "slot available," both pass the availability check, and both insert a booking record — all before either transaction commits. CWE-362 (race condition) and OWASP A04 (Insecure Design) both apply. A database-level UNIQUE constraint is the only mechanism that enforces the invariant atomically: the database serializes concurrent writes and rejects the duplicate at the storage layer, regardless of application concurrency.

## Severity rationale

Critical because application-level checks without database constraints provably fail under concurrent load, producing confirmed double-bookings that require manual remediation and refunds.

## Remediation

Add a UNIQUE constraint to your schema so the database enforces the invariant even when application-level checks race. Add this in `prisma/schema.prisma` (or the equivalent SQL migration).

```prisma
model Booking {
  id        String   @id @default(cuid())
  slotId    String
  startTime DateTime
  status    String

  @@unique([slotId, startTime]) // database-level enforcement
}
```

Then handle the unique constraint violation in your handler and return a structured 409 Conflict response.

## Detection

- **ID:** `concurrent-request-handling`
- **Label:** Concurrent requests are handled safely
- **Severity:** `critical`
- **What to look for:** Count all database-level concurrency controls protecting booking creation: UNIQUE indexes on slot + time columns (check `schema.prisma`, migration files, or `CREATE TABLE` statements), serializable transaction isolation (`isolation: 'Serializable'`, `SET TRANSACTION ISOLATION LEVEL SERIALIZABLE`), pessimistic locking (`FOR UPDATE`), or advisory locks. Also check for application-level-only patterns (find-then-insert without constraints). Enumerate: "X concurrency control mechanisms found: [list types]."
- **Pass criteria:** At least 1 database-level concurrency control must exist. The schema must include a UNIQUE constraint preventing overlapping bookings (e.g., `@@unique([slotId, startTime])` in Prisma, `UNIQUE(slot_id, start_time)` in SQL), OR transactions use `SERIALIZABLE` isolation level, OR row-level locking (`FOR UPDATE`) is used. Report: `"X concurrency controls found: [UNIQUE constraint on (slotId, startTime) in schema.prisma | SERIALIZABLE isolation | FOR UPDATE locking]."`
- **Fail criteria:** Application-level checks only (check availability then insert without db constraints or locking). This is the number 1 cause of double bookings in production. Do NOT pass when the only protection is a `findFirst`/`count` check followed by a `create` — without a database constraint or transaction isolation, two concurrent requests can both pass the check and both insert.
- **Skip (N/A) when:** Never — this is critical for any booking system.
- **Detail on fail:** `"Booking creation relies on application-level 'findFirst' check followed by 'create' without database constraints or transactions. Vulnerable to race conditions under concurrent load."`
- **Cross-reference:** The conflict-check in Booking Creation verifies the application-level availability check that this database constraint backs up.
- **Cross-reference:** The transaction-atomicity check in this category verifies multi-table writes are atomic alongside this constraint.
- **Cross-reference:** The pessimistic-locking check in this category covers row-level locking as an additional concurrency layer.
- **Remediation:** Add a database-level UNIQUE constraint in your schema file (e.g., `prisma/schema.prisma` or migration SQL).

  ```prisma
  // In schema.prisma
  model Booking {
    id String @id @default(cuid())
    slotId String
    startTime DateTime
    // ... other fields
    @@unique([slotId, startTime]) // Prevents overlaps at DB level
  }
  ```

## External references

- cwe CWE-362
- cwe CWE-841
- owasp A04
- iso-25010 functional-suitability.functional-correctness

Taxons: data-integrity

HTML version: https://auditbuffet.com/patterns/ab-000543
