Skip to content

VNX-204: Observable Response Discrepancy

Reports login code that answers an unknown user or email ("User not found", "no such user", "Invalid username") with a different message from a wrong password, which lets an attacker enumerate accounts.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-204
Severity Low
SARIF level note
Kind sast
Languages Go, Java, JavaScript / TypeScript, Python, PHP, Ruby, C#
CWE CWE-204
CAPEC CAPEC-575
ATT&CK T1589
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 account-enumeration authentication observable-response cwe-204
Source internal/sast/rules/vnx-204.rego

Overview

VNX-204 maps to CWE-204: Observable Response Discrepancy. When a login form says “User not found” for one input and “Wrong password” for another, it tells an attacker which usernames or email addresses have accounts. That list is the starting point for credential stuffing, password spraying and targeted phishing.

What Gets Flagged

A string literal saying the user, username, account, email or login does not exist, is not found, unknown, invalid or not registered, within 20 lines of and in the same function as a distinct message saying the password is wrong. The user-not-found line is reported.

if user is None:
    return jsonify(error="User not found"), 401        # flagged
if not user.check_password(request.form["password"]):
    return jsonify(error="Incorrect password"), 401
raise AuthError, "#{email} doesn't exist" unless user  # flagged
raise AuthError, "Incorrect Password!" unless user.authenticate(password)

Not flagged: one combined message (“Invalid username or password”), a not-found message with no password message beside it (an admin lookup returning 404), log statements, test code, messages in comments, and messages in different functions. Timing differences between the two branches are covered by VNX-205.

Remediation

Return the same message, status code and response shape for both cases:

if user is None or not user.check_password(request.form["password"]):
    return jsonify(error="Invalid username or password"), 401

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

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

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