VNX-305: Authentication Bypass by Primary Weakness
An auth middleware, decorator, permission class or servlet filter that lets a request through because a token, API key or Authorization header is present, without verifying it.
| Field | Value |
|---|---|
| Rule ID | VNX-305 |
| Severity | High |
| SARIF level | error |
| Kind | sast |
| Languages | Java, JavaScript / TypeScript, Python |
| CWE | CWE-305 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:H/AP:A/AL:A/IC:N/FC:LT/RP:N/RL:A/AV:I/AS:N/IN:A/SC:A/BI:H/DI:H/EX:H/EC:N/P:H |
| Tags | auth-bypass cwe-305 |
| Source | internal/sast/rules/vnx-305.rego |
Overview
VNX-305 maps to CWE-305: Authentication Bypass by Primary Weakness. It reports an authentication check that only tests whether a credential exists. A Node/Express middleware, a Python decorator, view or Django REST Framework permission, or a Java servlet filter or Spring interceptor reads a token, API key, Authorization header or session cookie from the request and then grants access (next(), return f(*args, **kwargs), call_next, chain.doFilter(...), or return True/true from an auth or permission method) when the value is merely non-empty, or as the very next statement after rejecting an empty one.
Not reported: a check whose condition or intervening lines verify, decode, validate, compare or look the credential up; a variable assigned from a verification call; a value held in the server-side session store (req.session.user, session.getAttribute), which the server itself put there at login; client-side route guards such as Angular canActivate; test files and comments. Verification hidden in another function between the read and the grant is not followed.
Why This Matters
The authentication scheme may be sound (signed JWTs, opaque API keys), but if the gate only checks that a header is present, any value authenticates. An attacker sends Authorization: Bearer x and reaches every protected route.
What Gets Flagged
// FLAGGED
const token = req.headers.authorization?.split(' ')[1];
if (token) return next();
if (!sessionToken) { return res.status(401).send('login required'); }
next();
# FLAGGED
token = request.headers.get("Authorization", "").replace("Bearer ", "")
if token:
return f(*args, **kwargs)
# FLAGGED: a DRF permission that returns the presence test
def has_permission(self, request, view):
return bool(request.headers.get("Authorization"))
// FLAGGED
String authToken = request.getHeader("Authorization");
if (authToken != null && authToken.startsWith("Bearer ")) {
chain.doFilter(req, res);
Not flagged: req.user = jwt.verify(token, secret); next();, if token and ApiToken.query.filter_by(value=token).first():, if (req.session.user) next();.
Remediation
- Verify the credential before granting access: check a JWT’s signature, issuer, audience and expiry, or look an API key up in a store and compare it in constant time.
- Attach the verified identity to the request (
req.user,g.user) and authorise from that, never from the raw header. - Fail closed: any error during verification must reject the request.
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-305
// nosec vnx-305
Or record an ignore rule: vulnetix ignore add --rule vnx-305 --reason "...". See Suppressing findings.