• Agents
  • Pricing
  • Blog
Log in
Get started

Security for apps built with AI. Paste a URL, get a report, fix what matters.

Product

  • How it works
  • What we find
  • Pricing
  • Agents
  • MCP Server
  • CLI
  • GitHub Action

Resources

  • Guides
  • Blog
  • Docs
  • OWASP Top 10
  • Glossary
  • FAQ

Security

  • Supabase Security
  • Next.js Security
  • Lovable Security
  • Cursor Security
  • Bolt Security

Legal

  • Privacy Policy
  • Terms of Service
  • Cookie Policy
  • Imprint
© 2026 Flowpatrol. All rights reserved.
Home/OWASP Top 10/API Top 10/API6: Unrestricted Access to Sensitive Business Flows
API6CWE-770CWE-840

The flow that works the same for one user and ten thousand bots
Unrestricted Access to Sensitive Business Flows

The endpoint works perfectly. A script that calls it 50,000 times works perfectly too.

New for 2023 — and already one of the most exploited patterns in AI-built apps.

Reference: API Top 10 (2023) — API6·Last updated April 7, 2026·By Flowpatrol Team
Unrestricted Access to Sensitive Business Flows illustration

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.

1
Map the flow
They sign up once, invite a friend, and watch the two requests: POST /api/referrals/invite and POST /api/referrals/redeem.
  • 2
    Automate it
    A 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.
  • 3
    Drain the budget
    By 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.
  • 4
    Pivot to resale
    The 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

    Vulnerable — the flow has no idea it is being abused
    // 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 });
    }
    Fixed — the flow knows what a real user looks like
    // 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

    Glossary

    Brute Force Protection (Rate Limiting)Broken Object Level Authorization (BOLA)

    What we find

    business logic abuse

    References

    • API6: Unrestricted Access to Sensitive Business Flows — official OWASP entry
    • OWASP API Security Top 10 (2023) — full list
    • CWE-770 on cwe.mitre.org
    • CWE-840 on cwe.mitre.org

    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