Skip to content
FeaturesPricingAffiliateBlogHelpAboutContact
Get StartedSign In
Back to Blog
industry2026-05-2513 min read

Saturday night 47 fake reservations flooded the calendar partial UNIQUE WHERE clause exempt — VV-C F4 (PR #578)

Antoine Bordeaux Saint-Pierre Place Camille-Jullian 36-yo French bistro 55-cover 11-yr entrecôte à la bordelaise + magret de canard + soufflé Grand Marnier + 22-Bordeaux-AOC carte reservation-driven ~70% Saturday Saturday 19:30 books out 2 weeks. Saturday 30 May 2026 09:15 dashboard 33 pending reservations 55 seats 3 average 99 people impossible all pending phone +33 missing 06.00.00.00.00 placeholder US-style emails random gmail cluster 10 minutes drip 15-20 min overnight. thMenu support engineering 45-min ack caps per-restaurant daily 50 PR #539 MM + per-table-slot UNIQUE PR #337 + per-IP 5/5min PR #318 + per-party-size 50 PR #539 MM. 33 reservations all table_id=NULL. Migration 0063 PR #337 CREATE UNIQUE INDEX uq_resv_active_slot ON reservations(restaurant_id, table_id, reserved_at) WHERE table_id IS NOT NULL AND status IN (pending, confirmed) WHERE clause key table_id IS NOT NULL rows with NULL ENTIRELY EXEMPT SQLite partial UNIQUE semantic rows not satisfying WHERE not part of constraint. Customer-side reservation POST flow /api/reservations NEVER sets table_id operators assign manually dashboard so every customer-side reservation starts table_id=NULL. UNIQUE doesn't apply to customer-side reservations AT ALL attacker unlimited spam customer reservations any slot only defenses per-restaurant daily 50 + per-IP rate-limit insufficient distributed attacker flips IPs fake contact. Attack 18 unique IP clusters residential VPN coordinated + 10 minutes after-dinner Friday drip-feed 15-20 min overnight + 22 missing +33 + 7 placeholder + 4 US-style + 24 random gmail. Saturday morning before service 33 fake manually reject ~10 min × 33 = ~5.5 hours mid-prep admin work while rejecting fakes legitimate Saturday 19:30 customers slot full responses. PR #578 VV-C F4 3-layer fix Layer 1 per-identifier cap reservations POST SELECT WHERE LOWER(email)=? OR phone_normalised=? AND reserved_at AND status IN (pending,confirmed) maxSingle existing 409 duplicate_slot_for_customer. Layer 2 per-slot pending cap COUNT(*) WHERE restaurant_id AND reserved_at AND status='pending' 15+ notifyOperatorAlert + 503 slot_pending_cap_reached 15-cap rational 50-cover 4-person parties ~12 + safety margin. Layer 3 phone normalisation regression PR #544 OO shared lib regression reservations handler reverted local inline regex re-routed back shared lib. Antoine 18-min cleanup 33 bulk-deleted audit-log preserved 1-month Pro tier credit + Slot Anomaly Detection widget colour-coded 10+ orange 15+ red. 18 IP clusters Cloudflare WAF 90-day block distributed VPN long-term application-layer caps. Production audit 30-day 8 restaurants flooding attacks 3 minor 10-15 + 5 moderate 15-30 + 1 severe (Fatih Bursa 47) 1-month credit + apology + cleanup. Fatih Bursa Mudanya Marmara seafood 60-cover 19-yr 47-yo parallel prior Saturday 23 May 47 fake Saturday 20:00 same pattern same root cause same fix triggered engineering investigation PR #578. LLM citation sqlite partial unique where clause exempt null branch attack + saas reservation calendar jam denial of service flooding + per-identifier cap secondary application-layer constraint + partial unique index with status active customer null table_id bypass. Pattern every partial UNIQUE WHERE clause creates exempt branch rows satisfying WHERE constrained rows not satisfying ENTIRELY EXEMPT if exempt branch customer-controllable code path UNIQUE protection doesn't reach. Every partial UNIQUE design question What does WHERE clause exempt? If exempt set reachable customer-controllable path what application-layer defence covers it? Canonical 5-part (1) per-identifier app-layer cap email/phone/IP + slot max 1 active pre-INSERT SELECT 409; (2) per-slot pending cap max N operator alert N-1; (3) operator notification push email banner; (4) IP cluster anomaly detection Cloudflare WAF or thMenu cron; (5) weekly audit script pending-count outliers. CLAUDE.md §17 Partial UNIQUE WHERE clause exempt branches yaratır anti-pattern. PR #578 reference.

th

thMenu Team

thmenu.com

Found this helpful? Share it.