VNX-400: Uncontrolled Resource Consumption from a request-supplied size
A number read from the HTTP request (Flask, Django, DRF, or an unbounded FastAPI int/float route parameter) sets a Python loop count, sleep, allocation, repetition or exponent with no upper bound, so one request can exhaust CPU, memory or a worker.
| Field | Value |
|---|---|
| Rule ID | VNX-400 |
| Severity | Medium |
| SARIF level | warning |
| Kind | sast |
| Languages | Python |
| CWE | CWE-400 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:M/AP:A/AL:A/IC:N/FC:LT/RP:N/RL:A/AV:I/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C |
| Tags | resource-consumption cwe-400 |
| Source | internal/sast/rules/vnx-400.rego |
Overview
VNX-400 maps to CWE-400: Uncontrolled Resource Consumption. CWE-400 is broad; this rule reports its most concrete line-level form in Python: a Flask, Django or DRF request value (request.args, form, values, json, GET, POST, data, query_params, headers, cookies), used directly or through a variable assigned from it in the 10 lines above, as
- the count of
range(...), - the duration of
time.sleep(...), - the size of
bytearray(),bytes(),os.urandom(),secrets.token_bytes()/token_hex()/token_urlsafe(), numpyzeros/ones/empty/full/arange,.read()or.recv(), - the width of
str.zfill(),ljust(),rjust()orcenter(), - the multiplier of a string or list repetition (
"=" * n,[x] * n), - the exponent of
**,
with no upper bound in between.
Not reported: a value bounded first (min(...), an if comparison of the variable, a max/min clamp reassignment), constants, environment and settings values, len() of the input, test files, comments and strings. A limit enforced in another function or by a schema validator is not seen, and unbounded work driven by other sources is out of scope.
Why This Matters
?count=1000000000 turns one request into a billion iterations, a gigabyte allocation or a worker asleep for a day. A handful of such requests takes the service down without any authentication.
What Gets Flagged
n = request.args.get("count", type=int)
return jsonify([make_code() for _ in range(n)]) # FLAGGED
delay = float(request.GET.get("delay", "0"))
time.sleep(delay) # FLAGGED
exp = int(request.form["exp"])
return str(10 ** exp) # FLAGGED
Not flagged:
n = min(request.args.get("count", 10, type=int), MAX_COUNT)
return jsonify([make_code() for _ in range(n)])
Remediation
- Clamp request-supplied sizes to a fixed maximum (
min(value, LIMIT)) or reject values above it with 400. - Enforce request body and upload size limits in the framework (
MAX_CONTENT_LENGTH,DATA_UPLOAD_MAX_MEMORY_SIZE).
References
Suppressing this rule
Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):
# nosec vnx-400
// nosec vnx-400
Or record an ignore rule: vulnetix ignore add --rule vnx-400 --reason "...". See Suppressing findings.