Back to Cheat Sheets

πŸ’Έ Denial of Service & Financial Resource Exhaustion

OWASP Serverless Top 10 - SAS-8

HIGH RISK

πŸ“‹ What Is It?

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 is allowed and starve legitimate traffic (a classic DoS). Because every invocation and millisecond is billed, that same flood becomes a financial attack-the platform keeps scaling and keeps charging, and the bill is the damage. This serverless-specific variant is called Denial of Wallet (DoW). The root cause is the accumulated absence of limits: no concurrency caps, no rate limiting, oversized timeouts/memory, self-triggering event loops, and no cost controls.

SAS-8 OWASP Rank
DoW Denial of Wallet
Shared Concurrency Pool

⚠️ Common Exploits

  • Unthrottled Public Endpoint: Anonymous, no API key, no WAF-replayed as fast as bandwidth allows
  • Maximally Expensive Invocation: Inputs that drive the long timeout & max memory
  • Recursive Loop: S3 write triggers a function that writes back to the same bucket
  • Fan-Out Amplification: One message expands into many via SNS/EventBridge
  • Retry/Poison Message: Fails after expensive work; re-billed on every redelivery
  • Downstream Exhaustion: Drains a DB connection pool or metered API
  • Neighbour Starvation: Flooding one uncapped function throttles the whole account

πŸ”΄ Attack Flow

1. Find a scaling entry point
(public endpoint, writable event source, self-loop)
↓
2. Make each unit expensive
(large payloads, long timeouts, big memory)
↓
3. Amplify - recursion, fan-out, retry storms
(invocations multiply for you)
↓
4. Let auto-scaling do the damage
(concurrency drains AND the bill climbs)
↓
5. IMPACT: Every function throttled (DoS) + bill explodes (DoW)!

❌ Vulnerable Code

# serverless.yml - no reserved concurrency; a flood on ONE function drains the # whole account's shared pool and throttles every other function. functions: report: # low-importance, PUBLIC, unlimited handler: handler.report timeout: 900 ← 15 minutes "just in case" memorySize: 3008 ← ~10x the cost of a 256 MB function events: - http: { path: /report, method: get } # no API key, no throttle, no WAF checkout: # critical path - no protected capacity handler: handler.checkout events: - http: { path: /checkout, method: post } # Recursive event loop: triggers on ANY object, writes back to the SAME bucket resize: handler: handler.resize events: - s3: bucket: media event: s3:ObjectCreated:* ← fires on the output too! # reads media/x.jpg -> writes media/x-resized.jpg -> ObjectCreated -> resize -> ... # No budget, no anomaly detection, no alarms. # A denial-of-wallet loop drives invocations 1000x; first signal is the invoice.

βœ… Secure Code

# serverless.yml - cap concurrency, throttle + quota the API, right-size limits provider: apiGateway: usagePlan: throttle: { rateLimit: 50, burstLimit: 100 } # steady-state + burst quota: { limit: 100000, period: DAY } # hard daily cap per API key functions: report: handler: handler.report reservedConcurrency: 10 ← hard ceiling: a flood self-throttles here timeout: 10 # as short as the task truly needs memorySize: 256 # right-sized; profile, don't guess-max events: - http: { path: /report, method: get, private: true } # require API key checkout: handler: handler.checkout reservedConcurrency: 100 # guaranteed capacity for the critical path # Break the loop: trigger only on incoming/*, write to a DIFFERENT prefix resize: events: - s3: { bucket: media, event: s3:ObjectCreated:*, rules: [ { prefix: incoming/ } ] } # Cap retries + dead-letter queue so a poison message isn't re-billed forever maximumRetryAttempts: 2 # SQS source: RedrivePolicy maxReceiveCount: 5 -> message moves to DLQ # AWS Budgets (NOTIFY) + CloudWatch invocation-spike alarm + Cost Anomaly Detection # For real enforcement: a responder Lambda that sets reservedConcurrency to 0.

βœ“ Prevention Checklist

  • Set per-function reserved concurrency caps
  • Know your account/region concurrency limit & headroom
  • Throttle + quota public endpoints (API Gateway)
  • Add a WAF rate-based rule at the edge
  • Use short timeouts; right-size memory
  • Enforce payload size & pagination limits
  • Separate input/output prefixes; recursion guards
  • Cap retries; use dead-letter queues (DLQs)
  • Timeout & circuit-break downstream calls; pool connections
  • Set AWS Budgets + Cost Anomaly Detection
  • Alarm on invocation count & estimated charges
  • Require auth on non-public functions

πŸ” Detection & Tools

Limits & Edge Controls:

Reserved Concurrency API Gateway Throttling Usage Plans / Quotas AWS WAF Rate Rules SQS DLQ

Cost & Observability:

AWS Budgets Cost Anomaly Detection CloudWatch Alarms Recursive-Invocation Detection

How to Test:

  • Confirm each function has a reservedConcurrency cap
  • Check public endpoints for throttle, quota, and WAF rules
  • Audit timeouts/memory for "just in case" oversizing
  • Trace event topologies for self-triggering loops
  • Verify DLQs and finite maxReceiveCount on queues
  • Confirm Budgets + invocation/billing alarms exist and page

🌍 Real-World

Described as incident classes-patterns repeatedly observed and documented across the industry; no dollar amounts or invocation counts are asserted, the lesson is the mechanism:

  • Denial-of-Wallet Cost Spike: A public function with no rate limiting, no reserved concurrency, and no cost alerting; automated abuse drives invocations up by orders of magnitude and the impact accrues unnoticed until it appears on the invoice. Developers have repeatedly reported unexpectedly large bills from this class of abuse.
  • Concurrency-Exhaustion DoS: With no per-function cap, one flooded or looping function consumes the entire shared pool and throttles unrelated functions-"noisy neighbour" starvation.
  • Recursive Event-Source Loop (Self-Inflicted): The classic S3β†’Lambdaβ†’same-bucket loop; a single event self-amplifies. Cloud providers now explicitly warn about it and offer built-in recursive-invocation detection.

πŸ“Œ Quick Tips

  • DO NOT deploy public functions with no concurrency cap
  • DO NOT write output back into a trigger source
  • DO NOT max out timeout/memory "just in case"
  • DO throttle at the edge and API layer
  • DO cap retries and use DLQs
  • DO bound cost with Budgets & alarms
  • DO remember alerts notify - caps enforce

πŸ“œ Compliance

Related Standards:

  • OWASP API Top 10 - Unrestricted Resource Consumption
  • NIST 800-53 SC-5 - Denial of Service Protection
  • CIS AWS Foundations Benchmark
  • AWS Well-Architected - Cost & Reliability
  • SOC 2 A1.1 - Availability