PHP's == and JavaScript's == coerce types before comparing - a numeric-looking string that evaluates to zero, or a '0e' magic hash that equals another '0e' hash, turns an authentication check into a bypass.
PHP's == operator and JavaScript's == operator coerce both sides to a common type before comparing. A login endpoint that compares a user-supplied token to a stored value with == can be bypassed by sending a numeric-looking string that PHP evaluates to the same integer as the token. A role check that tests if(role == 0) is true for the boolean false, the string '0', an empty string, and the integer 0 alike. None of these payloads look malformed. The confirming artifact is a boolean differential, not an error message.
PHP's loose comparison table has been a source of bypasses since PHP 4. When one side is a number and the other is a string, PHP converts the string to a number before comparing. The string '0e1234' converts to float 0, so '0e1234' == '0e5678' is true - both look like scientific notation and both evaluate to zero. That is the class of bypass used against legacy PHP hash-comparison code: a stored MD5 or SHA1 hash that starts with '0e' compares equal to any other '0e...' candidate. JavaScript applies similar rules: 0 == false, null == undefined, '1' == 1. Each coercion is deterministic and documented, but none of them match what a developer intends when the code is a security gate.
The confirming probe uses a benign but characteristic payload that demonstrates the coercion without obtaining a privileged session. For a hash-comparison endpoint, the probe sends a '0e...' token candidate and observes whether the server grants a session. For a numeric-string bypass (0 == 'admin'), it sends a pure integer 0 where a non-numeric string is expected and watches whether the response code changes. The confirming artifact is the differential: a request that would be rejected with a correctly typed value succeeds with the coerced equivalent. Baseline and probe are the two halves of the evidence - no actual credential is derived and no privileged action is taken beyond demonstrating that the boundary is open.
# Baseline: random token - server rejects it cleanly POST /api/login {"username":"alice","token":"randomstring"} HTTP/1.1 401 Unauthorized # Probe: '0e' magic-hash pattern - if stored hash starts with '0e', PHP coerces both to 0 POST /api/login {"username":"alice","token":"0e462097431906509019562988736854"} HTTP/1.1 200 OK Set-Cookie: session=... # boundary failed - coercion confirmed # Probe: numeric 0 where a role string is expected GET /admin/panel Authorization: Bearer 0 HTTP/1.1 200 OK # if(role == 0) was true for string 'admin'
PHP is the primary surface because its comparison table is unusually permissive, but the class extends to any language with implicit coercion rules. JavaScript's == has documented coercion paths that bypass null-checks and role comparisons. Ruby's == delegates to the object's own method, which third-party types can override to produce surprising equality. Python's custom __eq__ implementations can return True for unexpected comparisons. Across all of them the common thread is not the language - it is a security gate that uses == on a value an attacker controls the type of.
| Language | Coercion pattern | Bypass example | Confirming probe |
|---|---|---|---|
| PHP | 0e magic hash | '0e1234' == '0e5678' is true | Send a '0e...' token; observe session grant |
| PHP | Numeric string vs number | 0 == 'admin' is true | Send integer 0 where string role expected; observe 200 vs 401 |
| PHP | Type-juggling with arrays | 0 == array() differs across versions | Send array in scalar field; observe server error or unexpected pass |
| JavaScript | Falsy equality | 0 == false, '' == false | Send 0 or empty string where role level checked; observe permission change |
| JavaScript | null/undefined equality | null == undefined is true | Send null token; observe whether check short-circuits to success |
Severity is set by the access control gate that the coercion bypasses, not by the mechanism. A type-juggling bypass on an authentication endpoint - a token comparison that accepts a magic-hash value - is critical, because it grants arbitrary session access to any caller who knows the coercion pattern. The same class on a role-level check that gates an admin panel is also critical. A coercion that affects only a cosmetic boolean - a feature flag, a display preference - is low. In every case the fix is the same: replace == with the strict equality operator (=== in PHP and JavaScript), enforce explicit type declarations on comparison operands, and reject non-string inputs at the API boundary before they reach any comparison that guards access. A linter rule that flags == in security-sensitive comparisons catches most of the surface at zero runtime cost.
Type juggling is easy to miss in code review precisely because the comparison looks correct - the equality operator is present, the operands are what they should be, and the logic reads naturally. The confirming probe is the only way to establish that the comparison fails in the face of an attacker who controls the type, not just the value. The arithmetic nonce 62615533 (7919x7907) appears in the probe log to confirm the test run identity without carrying any real credential.