VNX-287: Improper Authentication: check that always succeeds
Detects an authentication routine stubbed to accept everyone: an authenticate/verify-password/verify-token function whose first statement is return true, an auth middleware that only calls next(), or a login_required decorator that returns the view unchanged.
| Field | Value |
|---|---|
| Rule ID | VNX-287 |
| Severity | High |
| SARIF level | error |
| Kind | sast |
| Languages | Java, JavaScript / TypeScript, Python |
| CWE | CWE-287 |
| 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 | authentication auth-bypass cwe-287 |
| Source | internal/sast/rules/vnx-287.rego |
Overview
VNX-287 maps to CWE-287: Improper Authentication. A placeholder written during development (“SSO will replace this”, “bcrypt is slow in dev”) is shipped, and the function every login or request goes through accepts anything.
The rule reports, in production code (test and fixture paths are skipped):
- a function or method named for an authentication decision (
authenticate*,check/verify/validate+password,credentials,login,token,jwt,api_key,signature,otp/mfa,session; JavaPasswordEncoder.matches) whose first statement isreturn True/return true, including a one-line Java/JS body and an arrow function whose body istrue; - an Express-style authentication middleware (
requireAuth,ensureAuthenticated,isLoggedIn,checkJwt, …) takingnextwhose first statement isnext(); - a Python
login_required/requires_authdecorator that returns the wrapped view unchanged.
What Gets Flagged
class PartnerBackend(BaseBackend):
def authenticate(self, request, username=None, password=None):
return True # FLAGGED
def login_required(view):
return view # FLAGGED
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) { return true; } // FLAGGED
const ensureAuthenticated = (req, res, next) => next(); // FLAGGED
What Is Not Flagged
- Routines whose first statement is a check, a lookup or a returned verification (
return bcrypt.compare(...)). - User-model flags (
is_authenticated,is_activeproperties) and authorisation predicates (has_permission,supports,isEnabled). - Middleware not named for authentication, test and fixture code, comments and string literals.
Remediation
Implement the real check, or fail closed until it exists:
def authenticate(self, request, username=None, password=None):
user = User.objects.filter(username=username).first()
if user and user.check_password(password):
return user
return None
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-287
// nosec vnx-287
Or record an ignore rule: vulnetix ignore add --rule vnx-287 --reason "...". See Suppressing findings.