VNX-791: Incomplete Filtering of Special Elements
Single-pass deletion of script tags, javascript: schemes, ../ sequences or shell metacharacters with replace()/re.sub()/replaceAll() in Python and JavaScript.
| Field | Value |
|---|---|
| Rule ID | VNX-791 |
| Severity | Medium |
| SARIF level | warning |
| Kind | sast |
| Languages | JavaScript / TypeScript, Python |
| CWE | CWE-791 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:M/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C |
| Tags | incomplete-filtering cwe-791 |
| Source | internal/sast/rules/vnx-791.rego |
Overview
VNX-791 maps to CWE-791: Incomplete Filtering of Special Elements. It reports hand-written sanitisers that delete a dangerous token in one pass:
- Python
str.replace(TOKEN, ''),re.sub(TOKEN, '', s)andPATTERN.sub('', s)wherePATTERN = re.compile(TOKEN)in the same file - JavaScript/TypeScript
replaceAll(TOKEN, ''),split(TOKEN).join(''),replace(/TOKEN/g, '')andreplace(PATTERN, '')whereconst PATTERN = /TOKEN/gin the same file
where TOKEN is a <script/<iframe/<object/<embed/<svg tag, a generic tag pattern built from word characters (<\w+..., <(?:\w+)..., which cannot match a nested <), a javascript: or vbscript: scheme, an event-handler attribute (onerror, on\w+…), a .. or ../ traversal sequence, or shell metacharacters. A character class of two or more shell metacharacters ([;&|]) is always reported; a single one (;, &, |, a backtick, $) only when a command (cmd, exec, subprocess, child_process, system(…) appears within six lines, because '$', '|' and '&' are deleted from prices, table cells and slugs far more often.
A replacement repeated in a while/do loop, escaping (replacing with an entity), an ellipsis ('...'), <[^>]*> (which absorbs a nested <), anchored patterns (reported by VNX-796) and JavaScript first-occurrence replace('x', ...) (reported by VNX-792 and VNX-793) are not reported.
Why This Matters
Deleting a token once reassembles it from nested input: <scr<script>ipt> becomes <script>, and ....// becomes ../. A denylist of shell characters leaves the ones it forgot (|, $(...), a newline).
What Gets Flagged
username = username.replace("<script>", "").replace("</script>", "") # FLAGGED
name = name.replace('../', '') # FLAGGED
return cmd.replace(';', '').replace('&', '') # FLAGGED
return input.replace(/<script>/gi, ''); // FLAGGED
const stripped = name.replaceAll('../', ''); // FLAGGED
Remediation
- Encode for the output context (template auto-escaping,
html.escape) instead of deleting tags. - For paths, resolve the full path and check it stays under the base directory.
- For commands, pass an argument list without a shell instead of filtering metacharacters.
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-791
// nosec vnx-791
Or record an ignore rule: vulnetix ignore add --rule vnx-791 --reason "...". See Suppressing findings.