VNX-1286: Improper Validation of Syntactic Correctness of Input
Detects request data parsed with no handling of malformed input: Python json.loads()/uuid.UUID()/Decimal()/fromisoformat() (and int()/float() of sources VNX-229 does not read) outside a try block, JavaScript JSON.parse() outside try, and parseInt()/Number() of route parameters and other sources VNX-229 does not read with no NaN check. A conversion VNX-229 reports is reported by VNX-229.
| Field | Value |
|---|---|
| Rule ID | VNX-1286 |
| Severity | Low |
| SARIF level | note |
| Kind | sast |
| Languages | JavaScript / TypeScript, Python |
| CWE | CWE-1286 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:L/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:L/DI:H/EX:L/EC:N/P:L |
| Tags | input-validation-syntactic cwe-1286 |
| Source | internal/sast/rules/vnx-1286.rego |
Overview
VNX-1286 maps to CWE-1286: Improper Validation of Syntactic Correctness of Input. A parser rejects malformed input by raising (Python, JSON.parse) or by returning NaN (parseInt, Number). When a request value goes straight into one with nothing handling the rejection, a malformed value fails the request with an unhandled exception (often a 500 with a stack trace) or flows on as NaN.
Reported:
- Python:
int(),float(),Decimal(),json.loads(),uuid.UUID(),datetime/datefromisoformat()andstrptime(),ipaddress.ip_address()/ip_network()applied to Flask/Django/DRF request data (request.args,form,values,GET,POST,data,body,json,cookies,headers,query_params,META), directly or through a variable assigned from it in the 10 lines above, outside atryblock and without anisdigit()/regex check first. - JavaScript/TypeScript:
JSON.parse()of request data (req.body/query/params/cookies/headers,ctx.query,ctx.request.body, Lambdaevent.body) outside atryblock;parseInt(),parseFloat()orNumber()of request data with no NaN check (isNaN,Number.isNaN,Number.isFinite,|| default, a falsy test) on the line or in the 6 lines after.
Not reported:
- A numeric conversion VNX-229 reports.
int()/float()of Flask/Django request data outsidetry, andparseInt()/parseFloat()/Number()ofreq.query/req.bodywith no NaN handling, are reported by VNX-229, the rule written for that conversion, so the same unhandled conversion is one finding, not two. The conversions VNX-229 does not read stay here:req.params,ctxand Lambdaeventsources,request.METAandrequest.body, and a conversion VNX-229 treats as handled but this rule does not. - Framework-typed access such as
request.args.get("n", type=int), constants, environment variables, file contents, comments and string literals.
What Gets Flagged
@app.route("/import", methods=["POST"])
def import_rows():
rows = json.loads(request.data) # FLAGGED: malformed JSON raises
size = int(request.META["CONTENT_LENGTH"]) # FLAGGED: not a source VNX-229 reads
router.get('/items/:id', (req, res) => {
const id = JSON.parse(req.params.id); // FLAGGED: outside try
const n = parseInt(req.params.n, 10); // FLAGGED: NaN never checked
});
What Is Not Flagged
try:
page = int(request.args.get("page", "1"))
except ValueError:
abort(400)
size = request.args.get("size", 20, type=int)
const page = parseInt(req.query.page, 10);
if (Number.isNaN(page) || page < 1) return res.status(400).end();
amount = int(request.form["amount"]) # reported by VNX-229, not repeated here
Remediation
- Parse request values inside
try/except(try/catch) and answer 400 on failure. - Check numeric conversions for
NaNbefore use, or supply a default. - Prefer a schema validator (pydantic, marshmallow, zod, Joi) or framework-typed accessors.
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-1286
// nosec vnx-1286
Or record an ignore rule: vulnetix ignore add --rule vnx-1286 --reason "...". See Suppressing findings.