VNX-289: Authentication Bypass by Alternate Name
Detects access checks that compare a name exactly when another spelling reaches the same thing: an if on the raw request path (getRequestURI, req.url/req.path, request.path) against a protected '/admin'-style literal or followed by a denial, and a reserved-username check without case folding.
| Field | Value |
|---|---|
| Rule ID | VNX-289 |
| Severity | High |
| SARIF level | error |
| Kind | sast |
| Languages | Java, JavaScript / TypeScript, Python |
| CWE | CWE-289 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:H/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:H/DI:H/EX:H/EC:N/P:H |
| Tags | auth-bypass-alternate-name path-normalisation cwe-289 |
| Source | internal/sast/rules/vnx-289.rego |
Overview
VNX-289 maps to CWE-289: Authentication Bypass by Alternate Name. A check that matches a name exactly is skipped by any other name for the same resource.
- A guard on the raw request path. An
ifcompares Javarequest.getRequestURI()/getRequestURL(), Nodereq.url/req.path/req.originalUrl/req.baseUrlor Pythonrequest.path/path_info/full_path/url(inline, or through a variable assigned from one in the 10 lines above) withstartsWith,equals,endsWith,includes,indexOf,==or===against a/...literal, and the literal names a protected area (/admin,/internal,/private,/manage,/actuator, …) or the next three lines deny the request./ADMIN,//admin,/admin/,/./admin,%61dminand/admin;xreach the same handler in common frameworks and skip the check. - A reserved account name compared case-sensitively. An
ifcompares a username/login/account name withadmin,administrator,root,superuser,system, … and rejects it within three lines, without lower-casing;Adminpasses.
What Gets Flagged
if (request.getRequestURI().startsWith("/admin") && session.getAttribute("admin") == null) { // FLAGGED
response.sendError(403);
}
if (req.originalUrl === "/api/private/export") { // FLAGGED
return res.sendStatus(401);
}
if username == "admin": # FLAGGED
raise ValueError("this name is reserved")
What Is Not Flagged
- A path that is lower-cased, normalised or decoded first, and Java
getServletPath(). - Routing comparisons against unprotected paths that do not deny (
req.url === '/health'). - Role checks (
user.role == "admin"), case-folded name checks, comments and string literals.
Whether the framework normalises the path before this code runs is configuration and is not judged.
Remediation
Enforce access on the matched route in the router or security framework (Spring Security requestMatchers, Express router-level middleware, Django decorators), not by comparing strings. Where a comparison is unavoidable, compare a canonical form: decode, normalise, and lower-case the path, and casefold() names after Unicode normalisation.
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-289
// nosec vnx-289
Or record an ignore rule: vulnetix ignore add --rule vnx-289 --reason "...". See Suppressing findings.