VNX-654: Reliance on a Single Factor in a Security Decision
Reports an if/elif that grants access (next(), login, a session admin flag, return True) because the client address or a Referer/X-Forwarded-For/X-Real-IP header matched, with no authenticated identity in the condition.
| Field | Value |
|---|---|
| Rule ID | VNX-654 |
| Severity | Low |
| SARIF level | note |
| Kind | sast |
| Languages | JavaScript / TypeScript, Python |
| CWE | CWE-654 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:L/AP:A/AL:A/IC:N/FC:LT/RP:N/RL:A/AV:I/AS:N/IN:A/SC:A/BI:L/DI:H/EX:L/EC:N/P:L |
| Tags | authentication ip-allowlist single-factor cwe-654 |
| Source | internal/sast/rules/vnx-654.rego |
Overview
VNX-654 maps to CWE-654: Reliance on a Single Factor in a Security Decision. It reports a condition that tests the client’s network origin and a branch that grants access on that alone.
- Origin read: Python
request.remote_addr,request.access_route,request.client.host,REMOTE_ADDR,HTTP_X_FORWARDED_FOR,HTTP_X_REAL_IP,HTTP_REFERER,request.referrerand the X-Forwarded-For/X-Real-IP/X-Client-IP/Referer headers; JavaScriptreq.ip,req.ips, Koactx.ip/ctx.request.ip,.remoteAddressand the same headers. It can be read directly or through a variable assigned a few lines above. - Comparison:
==,===,in,includes,startswith/startsWith,indexOf, a regextest. - Grant in the branch:
return next()/next()/await next(),login()/login_user(), a session admin/user/authenticated flag,is_admin = True,return True, a decorator returning the wrapped view.
Not reported: a condition that also checks the authenticated user, session, token or password, negated checks and blocklists, logging, rate limiting, region lookups, a grant behind a nested check, test files, comments and string literals.
Why This Matters
X-Forwarded-For and Referer are written by the client. A real address is shared behind NAT and proxies, and “localhost” is exactly where an SSRF request comes from. None of them proves who the caller is.
What Gets Flagged
if request.remote_addr == "127.0.0.1": # FLAGGED
return f(*args, **kwargs)
if (OFFICE.includes(req.ip)) { // FLAGGED
return next()
}
# NOT FLAGGED: address plus an authenticated user
if request.remote_addr in ALLOWED and current_user.is_authenticated:
return f(*args, **kwargs)
Remediation
- Authenticate the caller (session, token, mTLS) and use the network check only as an additional restriction.
- Never trust X-Forwarded-For unless a known proxy sets it; configure the framework’s trusted-proxy list instead.
References
- CWE-654: Reliance on a Single Factor in a Security Decision
- CWE-290: Authentication Bypass by Spoofing
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-654
// nosec vnx-654
Or record an ignore rule: vulnetix ignore add --rule vnx-654 --reason "...". See Suppressing findings.