Every product has a flow that is expensive when a human uses it and catastrophic when a script does. Signup. Checkout. Referral codes. Comment posting. The route is not broken. It is just willing to run a million times in a row.
A sensitive business flow is any route whose value does not scale with how many times it is called. Signup, checkout, referral redemption, ticket purchase, comment posting. Unrestricted access means nothing stops a single actor from running it ten thousand times in a row while the system thinks everything is fine.
What your AI actually built
You asked for a signup route. A referral bonus. A 'claim your free trial' button. The model built exactly what you described — a clean handler that validates input and writes a row.
What it did not build was the business rule around it. Nothing says 'one signup per phone number per day,' or 'at most three referral redemptions from the same device,' or 'a real human does not claim 2,000 promo codes in a minute.' Those are product rules, and the prompt never mentioned them.
So the route is correct and the feature is broken. The first bot to find it takes every free credit, every referral bonus, every seat in the launch queue — and the logs look like healthy traffic.
How it gets exploited
A new app ships a 'invite a friend, both get $10 in credits' referral flow. The attacker notices.
- 1Map the flowThey sign up once, invite a friend, and watch the two requests: POST /api/referrals/invite and POST /api/referrals/redeem.
- 2Automate itA 30-line script spins up disposable emails from a catch-all domain and runs the two requests in a loop. No captcha, no rate limit, no device fingerprint.
- 3Drain the budgetBy morning the script has claimed 18,000 referral bonuses. The startup wakes up to a Stripe balance at zero and a promo budget at minus forty thousand dollars.
- 4Pivot to resaleThe same pattern works on the free-trial flow. The attacker lists trial accounts on a Telegram channel for two dollars each.
The API never failed. Every request returned 200. The business failed — because the flow had no concept of 'too many, too fast, from the same person wearing different hats.'
Vulnerable vs Fixed
// app/api/referrals/redeem/route.ts
export async function POST(req: Request) {
const { code, newUserId } = await req.json();
const referral = await db.referral.findUnique({ where: { code } });
if (!referral) return Response.json({ error: 'Invalid' }, { status: 400 });
await db.credit.create({ data: { userId: newUserId, amount: 10_00 } });
await db.credit.create({ data: { userId: referral.ownerId, amount: 10_00 } });
return Response.json({ ok: true });
}// app/api/referrals/redeem/route.ts
export async function POST(req: Request) {
const { code, newUserId } = await req.json();
const device = getDeviceFingerprint(req);
// Per-device, per-day cap on redemptions
const recent = await db.referralRedeem.count({
where: { device, createdAt: { gte: since(24) } },
});
if (recent >= 3) return Response.json({ error: 'Too many' }, { status: 429 });
// One redemption per phone-verified identity
const user = await db.user.findUnique({ where: { id: newUserId } });
if (!user.phoneVerified) {
return Response.json({ error: 'Verify phone first' }, { status: 403 });
}
await db.$transaction([
db.credit.create({ data: { userId: newUserId, amount: 10_00 } }),
db.credit.create({ data: { userId: user.id, amount: 10_00 } }),
db.referralRedeem.create({ data: { device, userId: newUserId } }),
]);
return Response.json({ ok: true });
}The fix is not a rate limit on the endpoint. It is a rate limit on the business meaning of the endpoint — per device, per verified identity, per day. Rules like 'one per human' do not come for free. You have to write them.
A real case
Promo abuse drained a referral budget in a single night
A consumer app with a 10-dollar signup bonus lost roughly forty thousand dollars in one evening when a bot farm walked the referral flow unchallenged — the API was fine, the business rule was missing.
Related reading
References
Find the flows that work too well.
Flowpatrol replays your signup, referral, and checkout flows from many identities and shows which ones never say no. Five minutes. One URL.
Try it free