Skip to content

VNX-565: Reliance on Cookies without Validation and Integrity Checking

A security decision is taken on a plain, unsigned cookie that names identity or privilege (role, admin, user_id, username...), or such a cookie is written without a signature, in JavaScript/TypeScript, Python and PHP.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-565
Severity Medium
SARIF level warning
Kind sast
Languages JavaScript / TypeScript, PHP, Python
CWE CWE-565
CAPEC CAPEC-66
ATT&CK T1190
CWSS vector CWSS:1.0/TI:M/AP:A/AL:A/IC:N/FC:LT/RP:N/RL:A/AV:I/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C
Tags cookie-auth cwe-565
Source internal/sast/rules/vnx-565.rego

Overview

VNX-565 maps to CWE-565: Reliance on Cookies without Validation and Integrity Checking. It reports code that trusts a cookie the client can set to anything: a role, an admin flag, a user id or a user name read from a plain cookie and used to decide access or to look up an account.

Why This Matters

Cookies are request input. Anyone can open the browser’s developer tools, or use curl, and send role=admin or userid=1. Unless the server signed the value and checks the signature, or keeps the fact in a server-side session, a cookie says nothing about who the user is.

What Gets Flagged

const userId = req.cookies.userId;               // FLAGGED: used for the lookup below
const user = await User.findByPk(userId);
res.cookie('user_id', user.id);                  // FLAGGED: written unsigned
obj = Account.objects.filter(userid=request.COOKIES['userid'])[0]   # FLAGGED
$role = isset($_COOKIE['user_role']) ? $_COOKIE['user_role'] : 'guest';   // FLAGGED
setcookie('user_role', 'guest', time() + 3600, '/');                       // FLAGGED

An identity cookie written unsigned is flagged too (res.cookie('username', user.name), setcookie('user_id', ...)).

Not flagged: signed cookies (req.signedCookies, ctx.cookies.get(name, { signed: true }), res.cookie(..., { signed: true }), Django get_signed_cookie/set_signed_cookie), a value verified on the same or next two lines (jwt.verify, itsdangerous loads), session-id, CSRF and preference cookies, cookies that are only displayed, test files, comments and string literals. VNX-472 also reports privilege fields read from req.cookies in JavaScript.

Reported by another rule, not by VNX-565:

if (req.cookies.role === 'admin') { ... }        // VNX-784: a security decision on a cookie
res.cookie('role', user.role, { httpOnly: true }); // VNX-642: authorization state written to the client
if request.COOKIES.get('admin') == "1":          # VNX-784
    return HttpResponse("welcome admin")
html.set_cookie("admin", "1", max_age=200)       # VNX-642

A cookie named for a privilege or login state (admin, role, is_staff, logged_in, access_level…) that is compared or tested on its line, or assigned to a variable that a condition uses within 15 lines, is reported by VNX-784. An Express res.cookie() or Python set_cookie() of a cookie whose whole name is a privilege flag or role is reported by VNX-642. Each problem is reported once, by the rule that names it most precisely. VNX-565 keeps lookups, identity cookies (user_id, uid, username, email), PHP setcookie() and the other shapes.

Remediation

  1. Keep identity and privilege in a server-side session, keyed by an unguessable session id.
  2. If a cookie must carry them, sign it (cookie-parser secret with signed: true, Django set_signed_cookie, itsdangerous) or use a verified token (JWT with jwt.verify), and reject values that fail the check.
  3. Re-check the role against the user record on the server before any privileged action.

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-565
// nosec vnx-565

Or record an ignore rule: vulnetix ignore add --rule vnx-565 --reason "...". See Suppressing findings.

Edit this pageSources: cli/internal/sast/rules/vnx-565.rego, cli/internal/sast/docs/vnx-565.md
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.