AP-0502AvailabilitySeverity · High

One cheap request that stops the product

A single request that is cheap to send and expensive to serve can slow or stop the product for everyone. An unbounded search, an oversized upload or a deep nested payload does more damage than any flood.

At a glance

Controls
OWASP API4:2023 · SOC 2 CC7.2 · ISO 27001 A.12.1
LikelihoodCommon wherever an input has no ceiling
Effort to exploitLow: one crafted request
Blast radiusThe whole service, every user
What review catchesLittle: normal inputs work fine

Availability rarely fails to a flood of traffic; it fails to a single request that asks for far more work than it costs to make. A search with no upper bound, a report that scans everything, an upload with no size limit, a regular expression that backtracks, a nested payload that explodes when parsed. One request, cheap to send, can hold a worker, exhaust memory or lock a table long enough to stall the product for everyone else.

Why it happens

Inputs are validated for correctness, not for cost. A field checks that a number is a number, and never that it is below a sane maximum. Pagination defaults to a reasonable page size and lets the caller ask for a million. The expensive operation was written for the sizes seen in testing, and the size limit was never made explicit because ordinary use never reaches it.

How the attack unfolds

An attacker looks for the operation whose cost they control: the search that accepts any query, the export that has no row cap, the endpoint that parses whatever it is given. They send the largest, deepest, most expensive version the endpoint will accept, and repeat it just often enough to keep the workers busy. The product does not crash dramatically; it degrades, requests time out, and legitimate users are told to try again later.

It took two packets to crash a host that had been reviewed for twenty-seven years.The Record · OpenBSD, April 2026

Why review misses it

Every normal input works, so review and tests pass. The failure needs an input larger or deeper than anyone thought to try, and cost is not something a diff shows. The endpoint is correct for the sizes it was tested with, and silent about every size beyond them.

Where it hides

What a reviewer can look for in the code and in the behaviour, before anyone proves it.

  • An input has no documented, server-enforced upper bound on size, length, depth or page count.
  • A search, export or report can scan an unbounded amount of data on one request.
  • User-supplied text reaches a regular expression that can backtrack, or a parser that expands nested input.
  • A single request can hold a worker or a database lock long enough to affect other users.

A real instance

An analytics export accepted a date range with no limit and a group-by with no cap. A single request for several years of data grouped four ways ran for most of a minute, held a database connection, and made the dashboard time out for every other customer while it ran.

Details altered to protect the customer. Pattern, timing and outcome are as found.

How MATT tests it

The proof runs against the deployed product, on every release, whoever wrote the code.

  1. 01Find each operation whose cost the caller controls: search, export, upload, parse, report.
  2. 02Send the largest, deepest and most expensive input the endpoint accepts, and measure the work it does.
  3. 03Repeat at a low rate to test whether a few requests can exhaust workers, memory or connections.
  4. 04Confirm that a documented ceiling exists and is enforced on the server, not only in the interface.

The evidence

Before the fix
  1. GET /search?q=*&limit=1000000200 · 22sFull scan holds a worker; others queue behind it
  2. POST /import (nested payload)200 · OOMParser expands the payload until the process runs out of memory
After the fix
  1. GET /search?q=*&limit=1000000400 Bad RequestPage size capped server-side; query cost bounded
  2. POST /import (nested payload)413 Payload Too LargeSize and depth limits refuse the request before parsing
The rule, in plain English

Every input must have a documented upper bound, enforced server-side, and no single request may exceed a fixed budget of compute.

Executable check

Each cost-bearing endpoint must reject inputs beyond its documented bound and stay within its compute budget, on every release.

Every rule MATT holds →

What the fix looks like

  1. 01

    Bound every input

    Give each input a documented maximum size, length, depth and page count, enforced on the server.

  2. 02

    Budget the work

    Cap the compute, rows and time any single request may consume, and reject the ones that would exceed it.

  3. 03

    Degrade, do not fall

    Isolate expensive operations so one abusive request cannot take the whole product down with it.

A check that was never written is found by proving the deployed behaviour, fixed with the engineer who shipped it, and kept fixed by running the control on every change. What is ExploitOps? →

ExploitOps discovery call

Understand where your security loop breaks.

A 15-minute call with a MATT co-founder to understand your product and whether an ExploitOps Review is worth doing. If there is a real need, we scope one with the research team.