indexOf compared to -1

Vulnerability potential Low
DDoS potential None

arr.indexOf(x) >= 0 / !== -1 reads as a presence check; arr.includes(x) is shorter and clearer

Impact

arr.indexOf(x) !== -1 (or >= 0, or > -1) is the old idiom for “does the array contain x?”. It works, but it states the intent indirectly and invites two concrete mistakes. The first is an off-by-one boundary error: writing indexOf(x) > 0 instead of >= 0 silently treats an element found at index 0 as absent — a real correctness bug that passes most tests because the searched item is rarely first. The second is indexOf’s comparison semantics: it uses strict equality and therefore can never find NaN ([NaN].indexOf(NaN) is -1), so a presence check for NaN always reports “missing”. Both issues, plus the general readability cost, are why arr.includes(x) — which says exactly “contains” and handles NaN — is preferred.

Vulnerability potential

This is primarily a readability and correctness concern with little security weight. The only realistic security angle is indirect: if the presence check guards an allow/deny decision and the comparison boundary is wrong (> 0 missing index 0, or the NaN blind spot), the membership test can return the wrong answer and let a value slip past a filter it should have matched. That is a logic bug that could weaken a check, not a vulnerability inherent to indexOf, so the rating stays Low and a denial-of-service path is not credible.

Technical details

Array.prototype.indexOf returns the index of the first match or -1 when there is none, comparing with the SameValueZero-minus-zero rule of strict equality (===). Array.prototype.includes, added in ES2016, returns a boolean and compares with SameValueZero, which differs from === in exactly one way: it treats NaN as equal to NaN.

The NaN difference

[NaN].indexOf(NaN) === -1 (not found), but [NaN].includes(NaN) === true. Any presence check that must account for NaN is wrong with indexOf.

Boundary mistakes

The correct rewrites of includes are indexOf(x) !== -1 and indexOf(x) >= 0. The buggy variants indexOf(x) > 0 and indexOf(x) > -1-vs->= -1 confusions are easy to write and drop or admit the index-0 element. includes removes the comparison entirely, so the boundary cannot be wrong.

Strings and TypedArrays

String.prototype.includes and TypedArray.prototype.includes exist too, with the same advantage. Note includes is not available on plain objects or arguments; use Array.from/spread first, or Array.prototype.includes.call.

Catching the issue

Linters

ESLint’s unicorn/prefer-includes (from eslint-plugin-unicorn) flags indexOf(...) !== -1 / >= 0 presence checks and autofixes them to includes. Biome offers useArrayLiterals-adjacent style lints, and many shared configs include the unicorn rule.

Review

When a comparison against -1 is doing a yes/no membership test, prefer includes. Keep indexOf only when the position is actually needed (e.g. to splice at that index). Watch specifically for > 0 and for searches that could encounter NaN, which are the two cases where the indexOf form is not merely verbose but wrong.

How to reproduce

Observe the off-by-one (> 0 misses index 0) and the NaN blind spot, both fixed by includes.

const arr = ["a", "b", "c"];

console.log(arr.indexOf("a") > 0);    // false  -> BUG: "a" is at index 0
console.log(arr.indexOf("a") >= 0);   // true   (correct indexOf form)
console.log(arr.includes("a"));       // true   (clear and correct)

const nums = [1, NaN, 3];
console.log(nums.indexOf(NaN) !== -1); // false -> indexOf can't find NaN
console.log(nums.includes(NaN));       // true  -> includes can