Every server has finite memory, CPU, file handles and connections. CWE-400 is the class for a product that does not properly control the allocation and maintenance of a limited resource. If an attacker can trigger the allocation and the number or size is not controlled, the service runs dry.
It hits almost everything: web servers, parsers, image libraries, orchestrators, network devices, and, as MITRE now lists, AI and ML systems. Because it is a class level entry, many more specific weaknesses sit beneath it.
How it happens
The pattern is the same across technologies: an input the attacker controls determines how much work or memory the product uses, and nothing caps it.
MITRE's observed examples show the range:
- CVE-2019-19911: a Python library does not limit the resources used to process images that specify a very large number of bands, leading to excessive memory consumption or an integer overflow.
- CVE-2020-7218: a Go based workload orchestrator does not limit resource usage with unauthenticated connections, allowing a DoS by flooding the service.
- CVE-2020-3566: resource exhaustion in a distributed OS because of insufficient IGMP queue management, exploited in the wild according to CISA KEV.
- CVE-2009-2874: a product allows attackers to cause a crash through a large number of connections.
A minimal code example is a request handler that reads the whole body into memory:
@app.post("/upload")
def upload():
data = request.get_data() # no size limit
return process(data)
A client that sends a very large body, or many in parallel, consumes memory until the process is killed.
What an attacker gains
MITRE lists two kinds of impact:
- Availability. Crash, exit or restart, and CPU, memory or other resource consumption. The most common result is that the service becomes slow or unavailable.
- Access control. In some cases the product can be forced to fail open when resources run out, so security functionality is bypassed.
The second is easy to overlook. A service that skips an authorization check when a downstream call times out has turned a resource problem into a security problem.
How to find it
MITRE notes that static analysis has limited use here, except for system resources such as files, sockets and processes. It lists better options:
- Automated dynamic analysis can spot resource exhaustion with processes, memory and connections.
- Fuzzing can find it inadvertently, for example when the fuzzer generates a large number of connections or very large inputs.
Beyond those, test your own limits. Send an oversized body, open many idle connections, and upload a tiny file that expands into a huge one. Watch memory and file descriptor counts while you do it.
For dependencies, check whether the libraries you use appear in known resource exhaustion advisories. The free scan at gold.safeguard.sh/scan runs in your browser, needs no login, keeps the file on your machine and handles up to 100 dependencies. Reachability analysis then tells you whether your code actually calls the vulnerable function, which helps you rank the findings.
How to fix it
MITRE's main guidance, in plain steps:
- Design throttling into the architecture. The best protection is to limit the resources an unauthorized user can cause to be spent. Strong authentication and access control help stop attacks at the door, and the login itself should be protected against DoS.
- Limit database access, perhaps by caching result sets, to cut the cost per request.
- Track the rate of requests per user and block those above a defined threshold.
- Choose between recognizing an attack and denying that user access for a period, or throttling all requests uniformly. MITRE points out the tradeoffs: the first can lock out a valid user who is being impersonated, and the second is hard to do well and only raises the cost for the attacker.
- Put specific limits of scale on protocols.
In code, set explicit limits on size, count and time:
app.config["MAX_CONTENT_LENGTH"] = 5 * 1024 * 1024 # 5 MB request body cap
limiter = RateLimiter(max_requests=60, per_seconds=60)
Add timeouts to every outbound call, cap pool sizes, and bound recursion and decompression depth. Decide in advance what the service does when a limit is hit, and make sure the answer is to reject, never to skip a security check.
Try it yourself
Click through it at your own pace, or open it full screen.
Quick check
Why can resource exhaustion become an access control problem?
Some products fail open when resources run out, so security checks are skipped. MITRE lists bypass of protection mechanisms as a consequence.
Is static analysis the best way to find these bugs?
MITRE says it has limited utility here, apart from system resources like files and sockets. Dynamic analysis and fuzzing tend to find more.
Is blocking a heavy user always safe?
No. MITRE notes that an attacker who impersonates a valid user could get that user locked out, so blocks need care.