VNX-625: Permissive host/URL allow-list regular expression
Reports host and URL allow-list regular expressions with an unescaped dot in the host name, no end anchor after the domain, or a domain-only pattern with no start anchor.
| Field | Value |
|---|---|
| Rule ID | VNX-625 |
| Severity | Medium |
| SARIF level | warning |
| Kind | sast |
| Languages | Python, JavaScript / TypeScript, Go, Java |
| CWE | CWE-625 |
| 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 | permissive-url regex cwe-625 |
| Source | internal/sast/rules/vnx-625.rego |
Overview
VNX-625 maps to CWE-625: Permissive Regular Expression. Redirect, CORS and SSRF checks often use a regular expression to allow one host. Two mistakes make such checks easy to get around: an unescaped . matches any character (shop.example.com also accepts shopXexample.com), and a pattern that stops at the domain also accepts https://example.com.attacker.net.
What Gets Flagged
re.match(r"^https?://accounts.example.com/", url) # unescaped dots
re.match(r"https://([a-z0-9-]+\.)?example\.com", origin) # no end anchor
/^https:\/\/([a-z]+\.)?example\.com/.test(origin)
/^https:\/\/app\.example\.io(:\d+)?/.test(origin) // optional port does not anchor
/example\.com$/.test(origin) // no start anchor: evilexample.com
regexp.MustCompile(`^https://[a-z0-9-]+\.example\.com`)
A pattern counts as a host check when it starts with ^, contains ://, or is used with re.match. Not flagged: escaped dots with an end anchor ($, \Z, a following /), re.fullmatch() and Java’s whole-string matches() (for the missing-anchor form), re.sub() and other extraction uses, patterns without a host name, test files, comments and plain string literals.
Remediation
Escape every dot and anchor the end, or compare the parsed host exactly:
re.match(r"^https://([a-z0-9-]+\.)?example\.com(:\d+)?(/|$)", origin)
urllib.parse.urlsplit(url).hostname in {"example.com", "www.example.com"}
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-625
// nosec vnx-625
Or record an ignore rule: vulnetix ignore add --rule vnx-625 --reason "...". See Suppressing findings.