Skip to main content
interlace
Plugin: secure-codingRules

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):

  1. The loose-equality half is a duplicate. Every one of its 433 == / != findings is also reported by core eqeqeq. 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.
  2. The timing-attack half belongs elsewhere. Use node-security/no-timing-unsafe-compare, which is what meta.replacedBy points at.

The rule is still exported and still works. Enable it explicitly, or via the strict preset, 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

AspectDetails
CWE ReferenceCWE-697 (Incorrect Comparison)
SeverityHigh (security vulnerability)
Auto-Fix✅ Yes (replaces == with ===, != with !==)
CategorySecurity
ESLint MCP✅ Optimized for ESLint MCP integration
Best ForAll 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

ComponentPurposeExample
Risk StandardsSecurity benchmarksCWE-697 OWASP:A06 CVSS:5.3
Issue DescriptionSpecific vulnerabilityIncorrect Comparison detected
Severity & ComplianceImpact assessmentMEDIUM
Fix InstructionActionable remediationFollow the remediation steps below
Technical TruthOfficial referenceOWASP 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

IssueImpactSolution
🔒 SecurityType coercion can bypass checksUse strict equality (===)
🐛 BugsUnexpected type conversionsCompare type and value
🔐 ReliabilityHard-to-debug issuesPredictable comparisons
📊 Best PracticeViolates JavaScript best practicesAlways 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 match

Configuration

Default Configuration

{
  "secure-coding/no-insecure-comparison": "warn"
}

Options

OptionTypeDefaultDescription
allowInTestsbooleanfalseAllow insecure comparison in test files
ignorePatternsstring[][]Additional patterns to ignore

Example Configuration

{
  "secure-coding/no-insecure-comparison": [
    "warn",
    {
      "allowInTests": true,
      "ignorePatterns": ["x == y"]
    }
  ]
}

Best Practices

  1. Always use strict equality (===, !==) for all comparisons
  2. Nullish checks are exempt: value != null matches null AND undefined in one comparison, which is exactly why it is written that way. This rule does not report it, and rewriting it to !== null silently drops the undefined case. Core eqeqeq exempts it for the same reason.
  3. Type safety: Strict equality prevents accidental type coercion bugs
  4. 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 internally

Mitigation: Apply rule to wrapper implementations.

Dynamic Invocation

Why: Dynamic calls not analyzed.

// ❌ NOT DETECTED - Dynamic
obj[method](userInput);

Mitigation: Avoid dynamic method invocation.

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:

CodeWhy 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.