VNX-777: Regular Expression without Anchors
Allow-list validation regexes anchored at only one end, or bounded by a length and anchored at neither, tested with a search-semantics API; Ruby ^/$ line anchors in validation.
| Field | Value |
|---|---|
| Rule ID | VNX-777 |
| Severity | Medium |
| SARIF level | warning |
| Kind | sast |
| Languages | Go, Java, JavaScript / TypeScript, PHP, Python, Ruby |
| CWE | CWE-777 |
| CAPEC | CAPEC-97 |
| ATT&CK | T1557 |
| 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 | regex input-validation cwe-777 |
| Source | internal/sast/rules/vnx-777.rego |
Overview
This rule flags an allow-list regular expression (a single character class, \d, \w or . with +, * or {n,m}) used to validate a value when it is anchored at only one end, or is bounded by a length quantifier and anchored at neither, so the check passes as soon as part of the value conforms. It covers Python re.search/re.match, JavaScript RegExp.test and String.match/search, Go regexp.MatchString, Java Matcher.find()/lookingAt(), PHP preg_match and Ruby =~/match?, and in Ruby ^/$ (line anchors) used instead of \A/\z. Patterns are read at the call or from a named constant compiled in the same file. This maps to CWE-777: Regular Expression without Anchors.
Not reported: fully anchored patterns, re.fullmatch, String.matches, negated classes, unanchored patterns without a length bound (a “contains a digit” test is legitimate), match objects used to extract text, comments and strings.
Why This Matters
^[a-z0-9]+ accepts abc; rm -rf /, and a Ruby /^[a-z0-9]+$/ accepts abc\n<script> because $ matches at the newline. The validation passes and the rest of the value reaches the sink unchecked.
What Gets Flagged
if not re.match(r"[a-zA-Z0-9_]+", name): # FLAGGED: no end anchor
abort(400)
if (!/[0-9]{1,10}$/.test(req.params.id)) { // FLAGGED: no start anchor
validates_format_of :handle, with: /^[a-z_]+$/i, multiline: true # FLAGGED: line anchors
Remediation
if not re.fullmatch(r"[a-zA-Z0-9_]+", name):
abort(400)
if (!/^[0-9]{1,10}$/.test(req.params.id)) { ... }
validates_format_of :handle, with: /\A[a-z_]+\z/i
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-777
// nosec vnx-777
Or record an ignore rule: vulnetix ignore add --rule vnx-777 --reason "...". See Suppressing findings.