Safeguard
Cloud Security

Autoscaling Turned the Attack Into an Invoice

Every request was served, no alerts fired, the dashboards stayed green. The properties that made your infrastructure resilient are what made the attack work, and the only symptom arrives weeks later on a bill.

Karan Patel
Cloud Security Engineer
6 min read

Your service scaled perfectly under attack. Every request was served, no alerts fired, the dashboards stayed green. The bill arrived three weeks later.

Autoscaling converted an availability attack into a financial one, and the properties that made your infrastructure resilient are exactly what made the attack work. Nothing failed, so nothing told you.

This post is about designing for that, since the usual availability controls are tuned for the opposite failure. For whoever owns both the architecture and the cloud bill, which at a small company is the same person.

Why the traditional signals miss it

Availability monitoring watches for degradation: latency up, errors up, saturation. An autoscaled system under a cost attack has none of those. It adds capacity, serves everything, and reports health.

The signal is in the billing console, which updates slowly, is watched by finance rather than engineering, and is reconciled monthly. By the time anyone looks, the money is spent.

Two other things delay discovery. Cloud costs are lumpy and seasonal, so a spike does not obviously stand out. And the attack does not need to be large: a handful of requests to a genuinely expensive endpoint can cost more than a million requests to a cheap one.

Find your expensive endpoints

The exposure is not uniform. Almost all of it sits in a small number of operations where one request causes a lot of work:

  • Search and filtering, especially anything hitting a search cluster with a user-supplied query.
  • Report and export generation, which by design processes everything.
  • Image, video and document processing. One upload, substantial compute.
  • Anything calling a metered third-party API, where your cost is per call: model inference, enrichment providers, mapping, SMS.
  • Recursive or nested queries, where a GraphQL request can multiply into thousands of resolver calls.
  • Anything that fans out, one request producing many messages, each triggering work.

Cost per request varies by orders of magnitude across these, and your rate limit is almost certainly uniform. That mismatch is the whole problem: a limit sized for a cheap endpoint is meaningless on an expensive one.

Controls that fit

Rate limit by cost, not by request count. Assign a weight per endpoint and spend from a budget rather than a counter. A search might cost twenty units and a profile read one, from the same per-minute allowance.

This is the single change that matters most, because it makes the limit proportional to what the request actually consumes.

Bound concurrency instead of scaling it. For expensive work, a queue with a fixed number of workers converts a flood into a backlog rather than an invoice. Latency degrades, which is visible, which is the point. Autoscaling hides the problem; a bounded queue surfaces it.

Hard caps, not just alerts. A budget alert tells you after the fact. A hard limit stops the spend. For metered third-party APIs this is essential, because your cost there is uncapped by default and the provider is happy to serve.

Per-tenant cost attribution. Tag work with the account that caused it, so you can see which customer is generating spend. Without it, the bill is a single number and you cannot tell an attack from a large customer.

Require authentication for expensive operations. Anonymous access to a cheap read is fine. Anonymous access to a report generator is an invitation, and requiring a login means you at least know who to rate limit.

The alerts worth having

Rate of change, not absolute value. Spend per hour against the same hour last week. Absolute thresholds fire at month end and never catch a fast attack.

Per-tenant anomaly. One account consuming a large multiple of its normal volume. This catches both attacks and a customer's runaway integration, which is more common and costs the same.

Third-party API call volume, separately from your own compute, because it is billed separately and it is usually the most expensive per unit.

Queue depth on the expensive paths. If you took the bounded-concurrency advice, depth is your early warning, and it arrives in seconds rather than days.

All of these should page someone in engineering. A cost alert routed only to finance arrives through a monthly review, which is the wrong timescale.

Test it

The measurement worth doing once:

# What does one request to the expensive endpoint actually cost?
# Run 100 requests, then look at the delta in compute time,
# third-party call count, and storage operations.

seq 1 100 | xargs -P 10 -I{} curl -s -o /dev/null \
  -H "Authorization: Bearer $TOKEN" \
  "https://api.example.com/reports/generate?range=all"

Then extrapolate. If a hundred requests cost a pound, a determined attacker with a modest budget can cost you a great deal, and now you have a number rather than an intuition.

Also test that your limits behave. A rate limiter that permits ten requests a second to an endpoint costing fifty pence each is not a control, it is a spending authorisation.

The concession

Every control here trades capacity for predictability, and that trade is sometimes wrong. A genuine traffic spike from a product launch, a large customer onboarding, or a legitimate seasonal peak will hit the same limits, and a hard cap that stops real customers being served is a worse outcome than an unexpected bill.

So the placement matters more than the strictness. Bound the expensive paths and let the cheap ones scale freely. Set hard caps on third-party spend, where the ceiling is genuinely unbounded, and use alerting rather than caps on your own compute, where the worst case is more recoverable. And make sure a human can raise a limit quickly, because they will need to.

The implication

Autoscaling is a resilience feature that removes your ability to notice. The system absorbs the attack, and the only symptom arrives on an invoice weeks later.

So the question to ask of each expensive endpoint is not whether it would survive being hammered. It is what it would cost, and whether anyone would find out before the end of the month.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.