VNX-597: String compared with == or != instead of equals()/strcmp()
Reports Java comparisons of a String with a string literal or with another String variable by == or !=, and C comparisons of a char pointer with a string literal, which compare references or addresses rather than content.
| Field | Value |
|---|---|
| Rule ID | VNX-597 |
| Severity | Medium |
| SARIF level | warning |
| Kind | sast |
| Languages | Java, C |
| CWE | CWE-597 |
| 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 | java c string-comparison cwe-597 |
| Source | internal/sast/rules/vnx-597.rego |
Overview
VNX-597 maps to CWE-597: Use of Wrong Operator in String Comparison. In Java, == on two Strings compares references, so the result depends on whether both happen to be the same interned object. In C, comparing a char * with a string literal compares addresses.
The rule reports:
- in Java, any expression compared with a string literal by
==or!=(role == "admin",request.getParameter("a") == "x", also with the literal on the next line); - in Java, a comparison of two variables both declared
Stringwithin the 60 lines above; - in
.cfiles, an expression compared with a string literal.
It does not report equals, equalsIgnoreCase, Objects.equals or strcmp, comparisons with null, char literals (c == 'a'), C++ files (where std::string overloads ==), Kotlin (where == is equals), or operators inside comments and string literals. Boxed numbers and other objects compared by reference are VNX-595.
Why This Matters
A string read from a request, a file or a database is never the interned literal, so a check like if (role == "admin") is always false for real input and true only in a unit test that passes the literal. The reverse, if (token != expected), rejects or accepts depending on how the two values were built. Either way a security decision no longer depends on the value.
What Gets Flagged
if (role == "admin") { } // FLAGGED
if (request.getParameter("action") == "delete") { } // FLAGGED
return presented == expectedToken; // FLAGGED (both String)
if (input == "letmein") { } /* FLAGGED */
// NOT FLAGGED
if ("admin".equals(role) || Objects.equals(role, "root")) { }
if (role == null || c == 'a') { }
Remediation
- Java: use
"literal".equals(value)(null-safe) orObjects.equals(a, b); for secrets compare withMessageDigest.isEqualon the bytes. - C: use
strcmp/strncmp, or a constant-time comparison for secrets.
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-597
// nosec vnx-597
Or record an ignore rule: vulnetix ignore add --rule vnx-597 --reason "...". See Suppressing findings.