VNX-807: Reliance on Untrusted Inputs in a Security Decision
Reports an authorization decision taken on a value the client sends and can set to anything: an if/elif/else-if/switch condition, or a boolean assignment with a comparison, that reads a cookie, request header, query, body or path parameter (Express req.cookies/headers/query/body/params, with optional chaining, req.get()/req.header(); Flask/Django request.cookies/COOKIES/headers/META/args/GET/POST/form/values; Java request.getParameter/getHeader on any request or req variable, a Cookie from getCookies() compared by getName()/getValue(), Spring @RequestHeader/@CookieValue/@RequestParam parameters; FastAPI Header()/Cookie()/Query() parameters) where the input's name says what it decides (admin, role, root, superuser, staff, privilege, permission, access level, authenticated, authorized, logged-in) or it is compared with a privileged literal ('admin', 'administrator', 'root', 'superuser', 'staff', 'owner', 'moderator', 'auditor'). The value may be read on the same line, assigned to a variable up to 15 lines above, or destructured from the request object (const { role } = req.cookies). Not reported: server-side state (req.session, req.signedCookies, req.user, request.user, request.getSession(), isUserInRole), a condition that also consults server-side identity (req.body.role === 'admin' && !req.user.isAdmin, which guards against escalation), inputs that decide nothing privileged (theme, language, a non-empty check), logging or passing the value on without a decision, Referer/User-Agent checks, credential comparisons, string literals, comments and test files. A cookie named for a privilege or login state and decided on where it is read is reported by VNX-784 instead.
| Field | Value |
|---|---|
| Rule ID | VNX-807 |
| Severity | Medium |
| SARIF level | warning |
| Kind | sast |
| Languages | Java, JavaScript / TypeScript, Python |
| CWE | CWE-807 |
| 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 | security-critical-input cwe-807 authorization |
| Source | internal/sast/rules/vnx-807.rego |
Overview
VNX-807 maps to CWE-807: Reliance on Untrusted Inputs in a Security Decision. It reports code that decides who is an administrator, or who is authenticated, from a cookie, header or request parameter the client controls.
What Gets Flagged
// FLAGGED
if (req.query.admin === 'true') { return res.render('admin'); }
if (req.headers['x-user-role'] == 'admin') { ... }
const role = req.cookies.role;
if (role === 'admin') { ... }
# FLAGGED
if request.headers.get("X-Authenticated") == "true":
return HttpResponse("welcome admin")
cookie = request.COOKIES["cookie"]
if cookie.split("|")[0] == "admin":
return HttpResponse("welcome admin")
// FLAGGED
if ("true".equals(request.getParameter("isAdmin"))) { showAdmin(response); }
public String reports(@RequestHeader("X-User-Role") String role) {
if ("ADMIN".equals(role)) { return "all"; }
Not flagged: req.session.role === 'admin', req.signedCookies.admin, request.user.is_staff, request.isUserInRole("admin"), if (theme == "dark").
Reported by VNX-784, not VNX-807: a cookie named for a privilege or login state that is compared or tested on the line that reads it, or assigned there to a variable that a condition uses within 15 lines (if (req.cookies.isAdmin === 'true'), if request.COOKIES.get('admin') == "1":). That is a security decision on a cookie, the case CWE-784 names, so it is reported once, there. Other cookies, headers and parameters stay with VNX-807, which also owns a cookie value compared with a privileged literal (cookie.split("|")[0] == "admin"), so VNX-863 does not report that line.
// FLAGGED: destructured cookie, optional chaining, switch
const { role } = req.cookies;
if (role === 'admin') return next();
if (req.cookies?.isAdmin === 'true') return next();
switch (req.headers['x-user-role']) { case 'admin': /* ... */ }
# FLAGGED: FastAPI header parameter decides access
def delete_user(user_id: int, x_role: str = Header(default="user")):
if x_role != "admin":
raise HTTPException(status_code=403)
Not flagged: if (req.body.role === 'admin' && !req.user.isAdmin) return res.status(403), which checks the requested role against server-side identity.
Remediation
- Decide on state the server owns: the authenticated session, a verified token’s claims, or the user record.
- If a cookie must carry a role, sign it and verify the signature before reading it.
- Do not trust identity headers unless a gateway you control sets them and strips client copies.
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-807
// nosec vnx-807
Or record an ignore rule: vulnetix ignore add --rule vnx-807 --reason "...". See Suppressing findings.