PHP Type Juggling
Type Juggling is an abuse of PHP's loose comparisons. The loose equality operator == tries to convert both operands to a common type before comparing, instead of requiring them to be identical as the strict === does. That implicit conversion produces surprising equalities that break security checks: tokens, passwords or signatures validated with == can be bypassed by sending a value PHP considers "equal" after conversion.
The most famous case is magic hashes: if a hash starts with 0e followed only by digits, PHP reads it as scientific notation (0 * 10^n = 0), so two different hashes of that shape compare as equal. A password whose md5 is 0e... equals any other 0e...:
"0e123456" == "0e999999" // true: both evaluate to 0
md5("240610708") == md5("QNKCDZO") // true: two 0e... magic hashesKnown inputs whose hash has the 0e[0-9]+ shape (to paste straight into the field):
md5: 240610708 QNKCDZO aabg7XSs aabC9RqS
sha1: aaroZmOk aaK1STfY aaO8zKZF
# a value whose own text is "0e..." also works: many apps compare token==hashThe other classic comes through arrays in the input. If the code compares with == or passes an array to functions like strcmp, a favourable result is forced: strcmp(array, string) returns NULL in old PHP, and NULL == 0 is true, so the check passes. In a JSON API, just sending the unexpected type is enough:
// if the backend does if (strcmp($_POST['pass'], $real) == 0)
pass[]=x // strcmp(array, str) -> NULL -> NULL==0 -> bypass
// or in JSON, force a boolean/integer where a string is expected
{"password": true}Requirements. The backend must (1) be PHP and (2) compare sensitive data with == (or loose functions) instead of ===/hash_equals, and accept input arriving with an attacker-controllable type (array, boolean, 0e string). With strict comparison and type validation, juggling has no way in.
How to detect it. In the application log, the signature is parameters with an anomalous type for the field: [] suffixes that turn a value into an array (pass[]=), or strings shaped 0e[0-9]+ in password or token fields. A spike of login attempts with those patterns against the same endpoint gives the attack away.
Defence. Always compare with === (or with hash_equals() for secrets and signatures, which is also constant-time), validate and coerce the type of every input (is_string, explicit cast) before comparing, and do not trust implicit conversion. It overlaps with authentication bypass when the goal is to skip a login.