Back

SAS-8: Denial of Service and Financial Resource Exhaustion - Overview

What is Denial of Service & Financial Resource Exhaustion?

Denial of Service & Financial Resource Exhaustion is what happens when the two properties that make serverless attractive—it scales automatically and you pay per use—are turned against you. Because functions scale out on demand, an attacker can exhaust the finite concurrency your account or region is allowed and starve legitimate traffic (a classic denial of service). Because every invocation and every millisecond of execution is billed, that same flood becomes a financial attack: the platform keeps scaling and keeps charging, and the bill—not an outage—is the damage. This second, serverless-specific variant is widely called Denial of Wallet (DoW).

The weakness is not one broken function. It is the accumulated absence of limits: no per-function concurrency cap, no rate limiting on public endpoints, timeouts and memory sized far larger than needed, event sources wired into loops that amplify themselves, and no cost controls to notice or halt a spike. On traditional infrastructure a flood eventually hits a fixed ceiling—the server falls over and stops costing more. Serverless removes that ceiling by design: it elastically absorbs the load, so the natural failure mode shifts from “the box crashed” to “the meter kept running.”

Core Concept

Two linked risks from the same root (no limits):

  (1) Denial of Service (DoS)
      Concurrency is finite (account/region cap).
      One function hogging concurrency starves EVERY other function.
      Legitimate traffic is throttled (429/503) while the flood runs.

  (2) Denial of Wallet (DoW)  -- the serverless twist
      Billing is per-invocation + per-GB-second of duration.
      Auto-scaling means the platform NEVER refuses the load...
      ...it just keeps scaling and keeps charging.
      Damage = a massive invoice, not (only) an outage.

Bounded (safe):
  Concurrency  -> per-function RESERVED cap; account limit understood
  Endpoints    -> API Gateway throttling + usage-plan quotas + WAF rate rules
  Duration     -> short timeouts, right-sized memory
  Input        -> payload size limits, pagination caps
  Events       -> no self-triggering loops; DLQs; bounded retries
  Cost         -> Budgets + Cost Anomaly Detection + CloudWatch alarms

Unbounded (vulnerable):
  Concurrency  -> no reserved cap; one function can consume the whole account
  Endpoints    -> public, anonymous, no throttle, no quota, no WAF
  Duration     -> 15-min timeout + max memory "just in case"
  Input        -> unbounded body/loop drives long, expensive runs
  Events       -> S3-write loop / fan-out storm / uncapped retries
  Cost         -> no budget, no alarm; first signal is the bill

Why It's Critical for Serverless

Serverless concentrates several conditions that make resource exhaustion especially damaging:

Why Does This Matter?

Business Impact

Technical Impact

Technical Context

Why Serverless Turns a Flood Into a Bill

On a fixed server, throughput has a hard ceiling: once CPU and memory are saturated, the box refuses or drops work, and—crucially—the cost stops rising. Serverless deliberately removes that ceiling. The platform meets demand by launching more concurrent executions, and it charges for each one. So the same attack that would merely have degraded a server instead scales elastically and bills elastically. The finite resource is no longer CPU on one host; it is your account concurrency limit (availability) and your budget (money).

Traditional server under flood:
  requests -> queue -> saturate CPU/RAM -> drop/refuse -> cost is FLAT (fixed box)
  Failure mode: outage. Bill: unchanged.

Serverless under flood:
  requests -> auto-scale concurrency -> platform keeps accepting -> $$$ climbs
  Failure mode: (a) throttle once account limit hit  AND/OR  (b) huge bill.
  The "ceiling" that protected you is gone by design.

Common Exhaustion Scenarios

1. Unbounded / Expensive Functions

# A function provisioned "just in case":
  memorySize: 3008 MB      # billed per GB-second -> ~10x a 256 MB function
  timeout:    900 s        # a slow/looping request can run for 15 minutes
# One expensive invocation is costly; a flood of them is catastrophic.

Risk: Oversized memory and long timeouts multiply the cost and concurrency held by every single invocation.

2. No Rate Limiting on Public Endpoints

POST /api/render   (anonymous, no API key, no throttle, no WAF)
# An attacker replays this as fast as their bandwidth allows.
# Every request is a billable invocation; nothing caps the rate.

Risk: A public, anonymous endpoint with no throttle is an open tap on both concurrency and spend.

3. Recursive / Self-Triggering Invocations

S3 bucket "uploads"  --(ObjectCreated)-->  resizeFn
resizeFn writes the resized image BACK into "uploads"
        --(ObjectCreated)-->  resizeFn  --(ObjectCreated)-->  resizeFn ...
# An infinite loop that scales and bills itself with no external attacker.

Risk: An event source that a function feeds back into creates an unbounded, self-billing loop.

4. Amplification via Event Sources

# Fan-out: one message -> many messages -> many invocations
SNS/EventBridge fan-out, SQS re-drive without a cap, or a function
that publishes N events per invocation. Retries on failure multiply again:
  1 poisoned message -> repeated redelivery -> repeated (billed) invocations.

Risk: Fan-out and uncapped retries turn a small trigger into an exponential invocation storm.

5. Expensive Downstream Calls

# Each invocation calls a metered third-party API and a database:
  function()  ->  paid-translation-API  +  RDS query  +  another Lambda
# The function's own price is the SMALL part of the per-request cost.

Risk: Downstream metered services and connection pools can be exhausted or run up long before the function budget is.

Where the Limits Are Missing

LayerMissing LimitConsequence
Function configNo reserved concurrency capOne function drains the whole account's concurrency
Function configOversized memory / long timeoutEach invocation costs and holds far more than it needs
API GatewayNo throttling / usage-plan quotaUnbounded request rate becomes unbounded invocations
EdgeNo WAF rate ruleAnonymous floods reach the function directly
Event sourceSelf-trigger / no DLQ / uncapped retriesRecursive loops and retry storms self-amplify
Input handlingNo payload/pagination limitsLarge inputs drive long, expensive runs
Cost / observabilityNo Budgets, anomaly detection, or alarmsThe first signal of abuse is the invoice

Real-World Impact

The examples below are described as incident classes—patterns repeatedly observed and documented across the industry—rather than specific named breaches with invented figures. No dollar amounts or invocation counts are asserted here; the durable lesson is in the mechanism.

Case Class 1: Denial-of-Wallet Cost Spike Against a Public Function

Weakness:

Impact:

Root Cause: Auto-scaling with no rate limit and no cost control; nothing capped the invocation rate or connected the spike to a human in time to stop it.

Case Class 2: Concurrency-Exhaustion Denial of Service

Weakness:

Impact:

Root Cause: Concurrency treated as unlimited; without reserved caps, one function's load is every function's problem.

Case Class 3: Recursive Event-Source Loop (Self-Inflicted)

Weakness:

Impact:

Root Cause: An event topology wired into a cycle, with no idempotency check, prefix separation, or recursion guard to break it.

Prevalence and Statistics

Denial of Service & Financial Resource Exhaustion is a distinctive member of the OWASP Serverless Top 10 (as SAS-8) and echoes the broader industry concern of “Unrestricted Resource Consumption” (OWASP API Security Top 10). It is distinctive because serverless adds a financial dimension that traditional DoS does not have: the platform's greatest strength—seamless auto-scaling—is exactly what makes the attack pay off.

Rather than cite precise figures (which vary by source and year), the defensible picture is:

Note: exact percentages and dollar figures differ between reports and are easy to sensationalise. Treat any single number as illustrative; the durable takeaway is that auto-scaling without limits converts a flood into either an outage, a bill, or both—cheaply and reliably.

Common Misunderstandings

Myth 1: "Serverless auto-scales, so it can't be DoS'd"

Reality: Auto-scaling defers the failure; it does not remove it. Concurrency is finite at the account/region level, and cost is unbounded. You trade “the server fell over” for “everything is throttled and the bill exploded.”

Myth 2: "Pay-per-use means I only pay for real usage"

Reality: You pay for every invocation, including malicious and looping ones. Pay-per-use is exactly what makes denial-of-wallet possible: the attacker spends your money, not their own.

Myth 3: "One function's traffic can't affect my other functions"

Reality: Concurrency is a shared account pool. Without reserved caps, one function's flood starves every other function—the blast radius is the whole account, not one service.

Myth 4: "Retries make things more reliable, so they're always good"

Reality: Retries also multiply cost and concurrency. A function that fails expensively is billed for each automatic retry; without capped retries and dead-letter queues, failure becomes an amplifier.

Myth 5: "A recursive loop would be obvious immediately"

Reality: An S3-write or fan-out loop can scale to thousands of invocations in minutes while every individual invocation looks normal. Without a recursion guard and invocation/cost alarms, the first clear signal is the bill.

Myth 6: "A budget alert will stop the spending"

Reality: AWS Budgets and Cost Anomaly Detection notify; they do not automatically cap spend. Alerts must be paired with enforceable controls—reserved concurrency caps, throttles, and automated responses—to actually halt an attack.

How SAS-8 Differs from Related Issues

AspectDoS & Financial Exhaustion (SAS-8)Inadequate Monitoring (SAS-5)Broken Authentication (SAS-2)
Root causeNo limits on scaling, cost, or recursionNo security visibility across functionsWeak/absent identity checks
What it doesExhausts concurrency and/or runs up the billLets other attacks go unnoticedGrants unauthorised access
Typical fixReserved concurrency, throttling, timeouts, cost controlsLog, correlate, trace, alertEnforce authn/authz per function
DetectionInvocation & cost anomaly alarmsIt is the detection layerAuth-failure and anomaly logs

Key Takeaways

  1. Auto-scaling has no natural ceiling—serverless trades “the box crashes” for “concurrency is throttled and the bill keeps climbing.”
  2. DoS and Denial of Wallet are one attack—a flood that exhausts concurrency also runs up cost; pay-per-use makes availability and money the same target.
  3. Concurrency is shared and finite—without reserved caps, one greedy function starves the whole account.
  4. Recursion and retries amplify—self-triggering event sources and uncapped retries turn small events into unbounded, self-billing storms.
  5. Alerts are not enforcement—budgets and anomaly detection notify; caps, throttles, and automated responses are what actually stop the spend.

How to Identify if You're Vulnerable

Ask these questions about your serverless application:

If you answered "no" or "not sure" to several of these, a single loop or flood could throttle your application, run up your bill, or both.

Next Steps