Skip to content

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.

Updated 02 Nov 2026Checked against cli@de9b52a
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) and PATTERN.sub('', s) where PATTERN = re.compile(TOKEN) in the same file
  • JavaScript/TypeScript replaceAll(TOKEN, ''), split(TOKEN).join(''), replace(/TOKEN/g, '') and replace(PATTERN, '') where const PATTERN = /TOKEN/g in 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

  1. Encode for the output context (template auto-escaping, html.escape) instead of deleting tags.
  2. For paths, resolve the full path and check it stays under the base directory.
  3. 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.

Edit this pageSources: cli/internal/sast/rules/vnx-791.rego, cli/internal/sast/docs/vnx-791.md
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.