no-insecure-comparison
Detects insecure comparison operators (==, !=) that can lead to type coercion vulnerabilities
CWE: CWE-693
OWASP Mobile: OWASP Mobile Top 10
Detects insecure comparison operators (==, !=) that can lead to type coercion vulnerabilities. This rule is part of eslint-plugin-secure-coding and provides LLM-optimized error messages that AI assistants can automatically fix.
[!WARNING] Deprecated, and no longer in
recommended(removed 2026-07-31).Two reasons, both measured on a 1,470-file corpus (webpack, lodash, eslint-plugin-import, two NestJS boilerplates):
- The loose-equality half is a duplicate. Every one of its 433
==/!=findings is also reported by coreeqeqeq. Re-reporting another rule's findings under a CWE-697 security banner is noise, and no amount of narrowing changes that — it is a style check wearing a security hat.- The timing-attack half belongs elsewhere. Use
node-security/no-timing-unsafe-compare, which is whatmeta.replacedBypoints at.The rule is still exported and still works. Enable it explicitly, or via the
strictpreset, if you want it. It is simply not switched on for you.
As of 2026-07-31 the timing-attack detection matches secret keywords against
identifier word segments rather than as substrings of the whole expression's
source text. Previously if (key === "__non_webpack_require__") was reported as
a timing attack because the keyword list contained the bare word key; the same
relaxation also matched monkey, keyword, machine and author. That change
alone removed half the rule's corpus findings (443 → 221).
Quick Summary
| Aspect | Details |
|---|---|
| CWE Reference | CWE-697 (Incorrect Comparison) |
| Severity | High (security vulnerability) |
| Auto-Fix | ✅ Yes (replaces == with ===, != with !==) |
| Category | Security |
| ESLint MCP | ✅ Optimized for ESLint MCP integration |
| Best For | All JavaScript/TypeScript applications, especially security-sensitive code |
Vulnerability and Risk
Vulnerability: Insecure comparison occurs when using loose equality operators (== or !=) which perform type coercion before comparison.
Risk: This can lead to logic bypasses where different values are treated as equal (e.g., 0 == "0" or [] == 0). Attackers can often exploit this behavior to bypass authentication checks or authorization logic.
Error Message Format
The rule provides LLM-optimized error messages (Compact 2-line format) with actionable security guidance:
⚠️ CWE-697 OWASP:A06 CVSS:5.3 | Incorrect Comparison detected | MEDIUM
Fix: Review and apply the recommended fix | https://owasp.org/Top10/A06_2021/Message Components
| Component | Purpose | Example |
|---|---|---|
| Risk Standards | Security benchmarks | CWE-697 OWASP:A06 CVSS:5.3 |
| Issue Description | Specific vulnerability | Incorrect Comparison detected |
| Severity & Compliance | Impact assessment | MEDIUM |
| Fix Instruction | Actionable remediation | Follow the remediation steps below |
| Technical Truth | Official reference | OWASP Top 10 |
Rule Details
Insecure comparison operators (==, !=) use type coercion, which can lead to unexpected behavior and security vulnerabilities. This rule enforces strict equality (===, !==) which compares both value and type.
Why This Matters
| Issue | Impact | Solution |
|---|---|---|
| 🔒 Security | Type coercion can bypass checks | Use strict equality (===) |
| 🐛 Bugs | Unexpected type conversions | Compare type and value |
| 🔐 Reliability | Hard-to-debug issues | Predictable comparisons |
| 📊 Best Practice | Violates JavaScript best practices | Always use strict equality |
Detection Patterns
The rule detects:
- Loose equality:
==operator - Loose inequality:
!=operator
Examples
❌ Incorrect
// Insecure comparison with type coercion
if (user.id == userId) {
// ❌ Type coercion
// Process user
}
// Insecure inequality
if (value == undefined) {
// ❌ Type coercion
// Handle value
}
// Ternary with loose equality
const result = a == b ? 1 : 0; // ❌ Type coercion✅ Correct
// Strict equality - no type coercion
if (user.id === userId) {
// ✅ Type and value match
// Process user
}
// Strict inequality
if (value !== null && value !== undefined) {
// ✅ Explicit checks
// Handle value
}
// Ternary with strict equality
const result = a === b ? 1 : 0; // ✅ Type and value matchConfiguration
Default Configuration
{
"secure-coding/no-insecure-comparison": "warn"
}Options
| Option | Type | Default | Description |
|---|---|---|---|
allowInTests | boolean | false | Allow insecure comparison in test files |
ignorePatterns | string[] | [] | Additional patterns to ignore |
Example Configuration
{
"secure-coding/no-insecure-comparison": [
"warn",
{
"allowInTests": true,
"ignorePatterns": ["x == y"]
}
]
}Best Practices
- Always use strict equality (
===,!==) for all comparisons - Nullish checks are exempt:
value != nullmatchesnullANDundefinedin one comparison, which is exactly why it is written that way. This rule does not report it, and rewriting it to!== nullsilently drops theundefinedcase. Coreeqeqeqexempts it for the same reason. - Type safety: Strict equality prevents accidental type coercion bugs
- Consistency: Use strict equality throughout the codebase
Known False Negatives
The following patterns are not detected due to static analysis limitations:
Values from Variables
Why: Values stored in variables are not traced.
// ❌ NOT DETECTED - Value from variable
const value = userInput;
dangerousOperation(value);Mitigation: Validate all user inputs.
Wrapper Functions
Why: Custom wrappers not recognized.
// ❌ NOT DETECTED - Wrapper
myWrapper(userInput); // Uses dangerous API internallyMitigation: Apply rule to wrapper implementations.
Dynamic Invocation
Why: Dynamic calls not analyzed.
// ❌ NOT DETECTED - Dynamic
obj[method](userInput);Mitigation: Avoid dynamic method invocation.
Related Rules
no-unvalidated-user-input- Detects unvalidated user inputno-privilege-escalation- Detects privilege escalation vulnerabilities
Resources
Not a finding
This rule's subject is type coercion, and coercion needs two types. When both
operands are provably the same type, == and === do the same thing and there is
nothing to report:
| Code | Why it is silent |
|---|---|
var role = 'user'; if (role != 'user') | Both operands are provably strings. |
const r = `admin`; if (r == `admin`) | A template literal is a string by construction. |
if (x == null) | The idiomatic nullish check — it matches null and undefined, which is why it is written that way. Core eqeqeq exempts it for the same reason. |
If it fires, at least one operand's type is not provable here: a parameter, a member expression, a name written more than once. A variable reassigned between its declaration and the comparison can hold anything by the time the comparison runs, so it stays a finding.
Did this rule catch something? Star the repo to get new CWE coverage as we ship it — or follow the AI-code-security benchmarks behind these rules.