AI built coupon redemption (or credits, or one-per-user limits). It works, you shipped. What you actually shipped can be triggered many times at once, before it ever marks itself used.
What you shipped
The handler checks coupon.valid, then credits the user, then sets used = true — three separate steps. Between the check and the update, other requests can run.

How anyone exploits it
Fire 100 redemption requests at the same instant. All 100 read valid before any of them writes used = true, so all 100 pass the check and all 100 credit the user. One code, a hundred payouts.
Why you won’t catch it
Click redeem once and it works; click again and it’s blocked. The flaw only appears under simultaneous requests, which manual testing never produces.
Why AI does it
Check-then-act is the natural way to write “if it’s valid, use it.” It reads correctly and works for one request at a time — the gap only exists under concurrency.
The fix
Make the check-and-update a single atomic operation (a conditional update, a unique constraint, or a transaction):
await redeemOnce(coupon, user) // one atomic update; succeeds once

Check your app
- Redeem/limit/balance logic uses an atomic update, transaction, or unique constraint — not check-then-write.
- “One per user” is enforced by a DB constraint, not application code alone.
- Payment and credit operations are idempotent.
The bigger problem
A senior dev catches this by reflex. But if nobody senior reads the code, the broken version ships — it works in every test, because every test takes the happy path. The author and the reviewer are the same model with the same blind spot.
That’s the gap Velify is built to close: it reads your project and flags exactly this, in plain language, no terminal.
