| name | design-serverless-cost-protection |
| description | Use when deploying serverless functions at scale — setting reserved concurrency, SQS visibility timeouts, recursion detection, and budget alerts to prevent denial-of-service via financial resource exhaustion. |
| source | OWASP Serverless Top 10 SLS-8 (owasp.org/www-project-serverless-top-10/); AWS Lambda reserved concurrency documentation; AWS re:Invent "Serverless Security" (2022); Datadog State of Serverless 2023 |
| tags | ["security","owasp","serverless","lambda","cost-protection","dos","concurrency","cloud"] |
Design Serverless Cost Protection
Set reserved concurrency limits, configure SQS dead-letter queues with backoff, enable Lambda Recursion Detection, and configure AWS Budgets alerts — preventing runaway functions and financial denial-of-service where an attacker or bug can generate millions of invocations and thousands of dollars in minutes.
Why This Is Best Practice
Adopted by: OWASP Serverless Top 10 SLS-8 (Denial of Service and Financial Resource Exhaustion). AWS Lambda reserved concurrency is documented as the primary defense against both DoS and runaway cost. AWS re:Invent 2022 "Serverless Security" session lists SLS-8 as the most financially damaging class of serverless incident. Datadog's "State of Serverless" (2023) found that 12% of organizations reported unexpected Lambda cost spikes of >300% month-over-month, with most caused by event loop bugs or abuse of public-facing endpoints.
Impact: Unlike EC2 (fixed cost per instance), Lambda scales automatically to handle any traffic volume — a single misconfigured SQS trigger in an infinite retry loop was reported by a startup founder in 2019 to have generated $72,000 in Lambda and DynamoDB charges in one weekend. AWS documented a case where a Lambda recursive loop caused 100,000+ invocations per second for 3 hours before the account limit was hit. Public-facing API Gateway endpoints without rate limits are directly exploitable — a botnet sending 10,000 requests/second at $0.0000002/invocation costs $2,000/hour.
Why best: Reserved concurrency provides a hard cap — functions cannot scale beyond the reservation, preventing both cost exhaustion and cascade failures where one function consumes all account concurrency. The alternative (account-level concurrency limit only) allows a single function to starve all others in the account. Financial alerts provide a safety net when limits are misconfigured.
Sources: OWASP Serverless Top 10 SLS-8; AWS Lambda documentation on reserved concurrency; AWS re:Invent SVS401 "Serverless Security" (2022); Datadog State of Serverless (2023)
Steps
-
Set reserved concurrency on all production functions:
ProcessOrderFunction:
Type: AWS::Serverless::Function
Properties:
ReservedConcurrencyLimit: 100
PublicApiFunction:
Type: AWS::Serverless::Function
Properties:
ReservedConcurrencyLimit: 50
aws lambda put-function-concurrency \
--function-name my-function \
--reserved-concurrent-executions 100
Calculate appropriate limit: max_rps × avg_duration_seconds = required_concurrency
Add 20% headroom: required_concurrency × 1.2 = reserved_limit
-
Prevent SQS-triggered Lambda infinite loops with DLQ and backoff:
OrderQueue:
Type: AWS::SQS::Queue
Properties:
VisibilityTimeout: 90
RedrivePolicy:
deadLetterTargetArn: !GetAtt OrderDLQ.Arn
maxReceiveCount: 3
OrderDLQ:
Type: AWS::SQS::Queue
Properties:
Rules
- Every function with an external trigger (API Gateway, SQS, SNS, S3) must have a reserved concurrency limit — unlimited scaling is a financial risk, not just a performance feature.
- SQS → Lambda event source mappings must have a DLQ with
maxReceiveCount ≤ 5 — without DLQ, a poisoned message triggers infinite retries at full concurrency.
- Account-level Lambda concurrency limit (default 1000) is shared across all functions — reserve concurrency per critical function so one runaway function can't starve all others.
- Monitor the SQS DLQ depth — a growing DLQ indicates a processing failure that should trigger an alert, not just silent message accumulation.
Common Mistakes
ReservedConcurrencyLimit: -1 (unlimited) on all functions — the SAM default; acceptable during development but must be set before production deployment.
- SQS without DLQ — a message that consistently fails to process retries indefinitely until the retention period expires (4 days default), generating continuous Lambda invocations.
- Not accounting for downstream throttling — a Lambda with reserved concurrency of 1000 calling DynamoDB at 1000 RPS will hit DynamoDB throughput limits; size the entire call chain, not just Lambda.
- Budget alerts sent to email only — email alerts can be missed; route to SNS → PagerDuty/OpsGenie for financial anomalies that represent potential security incidents.