Back to Guides

    API4:2023 - Unrestricted Resource Consumption

    APIs that let clients control expensive operations without strong server-side limits can be abused to exhaust CPU, memory, and backend systems.

    1. What Is It?

    Unrestricted Resource Consumption occurs when an API allows clients to trigger expensive operations without enforcing safe limits on request cost.

    This is not only about high traffic. A single request can be enough to consume excessive CPU, memory, or backend capacity if the server blindly trusts attacker-controlled input.

    In the previous guide, we covered Broken Object Property Level Authorization and how field-level access issues can expose or modify sensitive data. This guide focuses on what happens when the client controls how much work the API performs.

    Read the API3 Guide

    2. Why It Matters

    Unrestricted Resource Consumption is dangerous because:

    • It can trigger denial-of-service conditions.
    • CPU and memory usage can spike from a small number of requests.
    • Backend systems can degrade for all users.
    • Infrastructure costs can increase sharply.
    • Stress conditions may expose internal diagnostics or secrets.

    In real-world systems, this can lead to:

    • Service instability and failed requests.
    • Expensive database or cache expansion.
    • Abuse of public endpoints without authentication.
    • Unexpected disclosure under error or stress conditions.

    Why OWASP classifies it as API4

    APIs often expose powerful operations such as search, filtering, export, expansion, or generation without controlling how expensive those operations can become. OWASP highlights this category because a client-controlled request can turn availability issues into direct security impact.

    3. How It Happens (Technical)

    This issue appears when client-controlled input directly determines how much work the backend performs.

    Common examples include pagination limits, recursive expansions, bulk exports, large uploads, or expensive pattern generation.

    Common technical causes:

    • No upper bound on search or pagination parameters
    • No timeout or execution guard for expensive operations
    • No cost budgeting for response generation
    • Public endpoints treated as low risk
    • Stress paths that expose internal debug information

    Core Issue

    api/search.py
    # vulnerable
    def search(term, limit):
        if limit < 1:
            raise HTTPException(status_code=400, detail="limit must be positive")
    
        expansion = [f"{term}-{i}-{term[::-1]}" for i in range(limit)]
        return {
            "count": len(expansion),
            "results_preview": expansion[:5],
        }
    The client controls how much server-side work is performed.

    Correct Direction

    api/search.py
    # safer
    MAX_LIMIT = 100
    
    def search(term, limit):
        if limit < 1:
            raise HTTPException(status_code=400, detail="limit must be positive")
    
        safe_limit = min(limit, MAX_LIMIT)
        expansion = [f"{term}-{i}-{term[::-1]}" for i in range(safe_limit)]
        return {
            "count": len(expansion),
            "results_preview": expansion[:5],
        }
    The server enforces a hard upper bound on request cost.

    Key concept: the client may request work, but the server must decide how much work is acceptable.

    Attacker’s Perspective

    From an attacker’s perspective, API4 is not only about sending many requests. It is about finding one parameter that makes each request much more expensive.

    • Find parameters that control response size or processing depth
    • Increase those values aggressively
    • Probe for thresholds where behavior changes under stress
    • Look for debug data or internal state exposed at high cost levels

    If one crafted request consumes disproportionate resources, the API is already in dangerous territory.

    4. Real-World Example

    A common example is a search endpoint that accepts an unbounded limit value and performs expensive expansion directly from user input.

    Example endpoint:

    GET /api/search?term=a&limit=12000

    Expected behavior: search size should be capped and stress conditions should never expose internal diagnostics.

    Vulnerable Logic

    api/search.py
    expansion = [f"{term}-{i}-{term[::-1]}" for i in range(limit)]
    data = {
        "count": len(expansion),
        "results_preview": expansion[:5],
    }
    
    if limit >= 10000:
        data["stress_debug"] = {
            "cache_state": "degraded",
            "flag": FLAG,
        }
    High-cost requests trigger both excessive processing and stress-only debug exposure.

    What is wrong: the API trusts an attacker-controlled limit value and performs synthetic expansion without any safe upper bound.

    Result: the request becomes expensive enough to change system behavior and reveal internal debug data that should never appear in a normal response.

    Common Variations

    • Unbounded Search: large limit or page values drive excessive response generation.
    • Recursive Expansion: nested or deep expansion paths create disproportionately expensive processing.
    • Large Upload Abuse: file size or parsing cost is not constrained safely.
    • Stress-Induced Disclosure: internal debug fields appear only when the system enters degraded states.

    5. How To Prevent

    1. Apply hard server-side limits

    Search size, page size, expansion depth, upload size, and other cost-driving parameters must be capped by the server.

    guards/request_cost.py
    MAX_LIMIT = 100
    
    safe_limit = min(limit, MAX_LIMIT)
    The server must enforce limits even when the client asks for more.

    2. Use execution guards

    Timeouts, concurrency limits, and worker controls help prevent one request from monopolizing backend resources.

    3. Treat public endpoints as high risk

    Public or unauthenticated endpoints should not be assumed safe. They often provide the easiest attack surface for cost abuse.

    4. Never expose stress or debug data

    Internal diagnostics should not appear in client responses, even when the system is overloaded or degraded.

    5. Monitor for disproportionate cost patterns

    Track request parameters, execution time, and abnormal thresholds so expensive paths are visible before they become outages.

    Key Principle

    • Limit cost at the server, not at the client
    • Assume a single request can be expensive enough to matter
    • Protect public endpoints with the same rigor as private ones
    • Never let degraded states change what the API reveals

    6. Detection Tips (Scanner Perspective)

    Detecting API4 requires testing how the backend behaves as request cost increases, not only whether the endpoint responds successfully.

    Common techniques:

    • Increase limit and pagination values aggressively
    • Measure response time, size, and behavioral changes
    • Find thresholds where the API becomes unstable
    • Check whether high-cost requests reveal debug fields or internal state
    • Test public endpoints as well as authenticated ones

    Key signal: if increasing a client-controlled parameter causes disproportionate backend work, unstable behavior, or stress-only disclosure, Unrestricted Resource Consumption is present.

    7. Final Takeaway

    Unrestricted Resource Consumption is not just a performance bug.

    It exists whenever:

    • The client can control request cost directly
    • Server-side limits are missing or too weak
    • Stress changes what the API returns
    • Availability weakness turns into disclosure or instability

    Every cost-sensitive endpoint should answer: Can a client force this API to do more work than the server safely allows?

    If the answer is yes, the API is already exposed.