• 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/API4: Unrestricted Resource Consumption
API4CWE-770CWE-400

The endpoint that will happily DoS your wallet
Unrestricted Resource Consumption

Every route has a price tag — CPU, memory, database rows, LLM tokens, SMS messages. Most are uncapped.

One of the most common API bugs — and the one most likely to hit your credit card before your security team.

Reference: API Top 10 (2023) — API4·Last updated April 7, 2026·By Flowpatrol Team
Unrestricted Resource Consumption illustration

Your API scales. That's the pitch. What you didn't notice is that it scales the attacker's costs too: one anonymous user can now mint you a five-figure AWS bill with a bash loop. The endpoint works exactly as designed. The design is what's missing.

Every API call consumes something: CPU, memory, database time, bandwidth, an LLM token bill, a carrier SMS fee. Unrestricted Resource Consumption is what happens when the API has no idea how much any request costs and no mechanism to stop a caller from making too many.

What your AI actually built

You asked for a /api/search endpoint that takes a query and a limit. The model delivered. No upper bound on the limit, no pagination ceiling, no cap on concurrent calls, no rate limit per caller.

Somewhere else in the app there is a /api/send-otp route that calls Twilio for every request, an /api/chat route that forwards to OpenAI with no token cap, and an /api/export route that materializes the entire database into a CSV on the fly.

Each of these is one feature the model wrote correctly. What it did not add — because you did not ask — is any notion of how much any of them costs to invoke and who is allowed to invoke them how many times.

How it gets exploited

An attacker finds the API surface of a SaaS product from its public docs. No login required for a few endpoints, login required for the rest.

1
Find the expensive endpoint
They look for the route that does the most work per call. /api/export/csv wins — it streams the whole projects table through a transformer.
  • 2
    Turn up the volume
    They call it in a loop from 50 IPs. The backend fans out to the database, which fans out to the read replica, which starts queueing. The service degrades for every real customer simultaneously.
  • 3
    Point at the expensive dependency
    On the unauthenticated /api/chat endpoint, every request costs 30 cents in LLM tokens. They run 10,000 requests an hour. The Anthropic bill for the day is $72,000.
  • 4
    Abuse the SMS endpoint
    Meanwhile /api/send-otp takes a phone number and sends a code. They pipe an entire country code range through it. Twilio charges per send. Nothing rate limits by IP, by user, or by recipient.
  • The app is still up, technically. Three different vendors are sending the founder urgent billing emails. Real customers can't load the dashboard. The only mitigation the team has is to pull the plug.

    Vulnerable vs Fixed

    Vulnerable — no caps, no limits, no ceiling
    // app/api/search/route.ts
    export async function POST(req) {
      const { query, limit } = await req.json();
    
      // limit: 1000000 is a perfectly legal request
      const results = await db.product.findMany({
        where: { name: { contains: query } },
        take: limit,
      });
    
      return Response.json(results);
    }
    Fixed — cap the inputs, cap the caller, cap the cost
    // app/api/search/route.ts
    import { z } from 'zod';
    import { rateLimit } from '~/lib/rate-limit';
    
    const SearchSchema = z.object({
      query: z.string().min(1).max(200),
      limit: z.number().int().min(1).max(50).default(20),
    });
    
    export async function POST(req) {
      const session = await getSession(req);
      if (!session) return Response.json({ error: 'Unauthorized' }, { status: 401 });
    
      const ok = await rateLimit(`search:${session.userId}`, { max: 60, window: '1m' });
      if (!ok) return Response.json({ error: 'Too many requests' }, { status: 429 });
    
      const { query, limit } = SearchSchema.parse(await req.json());
    
      const results = await db.product.findMany({
        where: { name: { contains: query } },
        take: limit,
      });
    
      return Response.json(results);
    }

    Three layers: a schema that caps the input (limit max 50, query max 200 chars), an auth check so anonymous floods bounce, and a per-user rate limit that stops even authenticated abuse. Apply the same three layers to anything that calls a paid API.

    A real case

    A single uncapped SMS endpoint cost one startup $28,000 in a weekend

    A common SMS pumping pattern — attackers send OTP requests to premium-rate numbers they control and split the carrier revenue — has drained countless startup budgets through uncapped /send-verification endpoints.

    Related reading

    Glossary

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

    What we find

    broken access control

    References

    • API4: Unrestricted Resource Consumption — official OWASP entry
    • OWASP API Security Top 10 (2023) — full list
    • CWE-770 on cwe.mitre.org
    • CWE-400 on cwe.mitre.org

    Find the endpoints that scale the wrong way.

    Flowpatrol maps your API, measures cost per call, and flags the routes that will ruin your month.

    Try it free