Bitwise Operator Applied To Boolean Operands
ID |
javascript.bitwise_in_boolean_context |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
JavaScript |
Tags |
CWE:480, control-flow, reliability |
Description
Reports & or | applied to operands that are plainly booleans, where && or || was meant. A single character was dropped, and both the evaluation order and the result type change with it.
An operand counts as plainly boolean when the language guarantees it: a comparison (===, !==, <, instanceof, in, …), a logical negation, a && / || sub-expression, or a boolean literal. Nothing else is assumed, which is what keeps a real bit mask quiet — flags & READ_MASK has two operands whose values the rule cannot know, so it stays silent even inside an if.
That is a deliberate departure from the wider reading of "a bitwise operator in a condition": if (bits & MASK) is the ordinary way to test a flag, and reporting it would make the rule useless in the code that uses bit masks most.
Rationale
// Bad
if (user !== null & user.isAdmin) { // throws when user is null
grant(user);
}
const ok = a > 0 | b > 0; // ok is 1 or 0, not true or false
-
Short-circuiting is gone. The guard on the left no longer protects the dereference on the right, so the expression throws on exactly the input the guard was written for.
-
The result is a number. It no longer compares equal to
true, it serialises as1, and it carries no information about which side was truthy. -
Every test written with a non-null user passes, so the failure arrives in production on the first null.
Remediation
Use the logical operator.
// Good
if (user !== null && user.isAdmin) {
grant(user);
}
const ok = a > 0 || b > 0;
When the intent really is a bitwise combination of two flags, compare them explicitly so the reader can see it is arithmetic and not logic:
// Good
const combined = (readable | writable) & ~locked;