VNX-581: Object Model Violation: Just One of Equals and Hashcode Defined
Reports a Java or Kotlin class that overrides equals(Object) without hashCode(), or hashCode() without equals(Object), judged per class including nested classes.
| Field | Value |
|---|---|
| Rule ID | VNX-581 |
| Severity | Medium |
| SARIF level | warning |
| Kind | sast |
| Languages | Java, Kotlin |
| CWE | CWE-581 |
| 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 | equals-hashcode object-model cwe-581 |
| Source | internal/sast/rules/vnx-581.rego |
Overview
VNX-581 maps to CWE-581: Object Model Violation: Just One of Equals and Hashcode Defined. Objects that are equal must have equal hash codes. A class that overrides only one of the two breaks that contract: HashMap, HashSet and caches miss entries, store duplicates, or fail to find a key that is present. That can defeat de-duplication, permission sets and lookups keyed by the object.
What Gets Flagged
The line declaring the lone method: public boolean equals(Object) or public int hashCode() in Java, and override fun equals(other: Any?) or override fun hashCode() in Kotlin. The pairing is judged per class, so a nested class that defines only one is reported even when its outer class defines both.
public class Sku {
@Override
public boolean equals(Object o) {
...
}
// no hashCode()
}
class Version(val major: Int, val minor: Int) {
override fun equals(other: Any?): Boolean { ... }
// no hashCode()
}
What Is Not Flagged
- A class that defines both.
- A Kotlin
data classor Javarecord, whose other method the compiler generates over the same components. - An
equalsoverload with another parameter type (equals(Range r)), which is a different mistake. - Calls of
hashCode()orequals()on other objects. - Test code, comments and string literals.
Remediation
- Override both, over the same fields:
Objects.equals(...)inequals,Objects.hash(...)inhashCode. - In Kotlin, a
data classderives both from its properties.
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-581
// nosec vnx-581
Or record an ignore rule: vulnetix ignore add --rule vnx-581 --reason "...". See Suppressing findings.