Back to Skills

type-juggling

PHP type juggling and weak comparison (`==`) bypass. Use when authentication, HMAC/signature checks, or token validation uses loose equality, numeric coercion, or hash comparisons without strict types — common in legacy PHP and CTF-style code paths.

1,297stars177forksUpdated 7/7/2026

Security Assessment

Low Risk(85/100)

Detected risks:

Secret Exposure([SKILL.md] password=)
Security Score85/100

About type-juggling

A security-testing playbook for PHP type juggling and weak-comparison bypasses. It applies when authentication, HMAC or signature checks, or token validation rely on loose equality (==), numeric coercion, or hash comparisons without strict types, patterns common in legacy PHP and CTF-style code. The stated first-pass goal is to prove that a server branch treats unequal secrets or tokens as equal through coercion, not to guess the real password.

Core content includes a truth table for loose comparison showing how numeric-looking strings, falsy values, and empty strings coerce, with explicit deltas between PHP 5/7 and PHP 8 (for example, 0 == 'foo' is true on PHP 7 and earlier but false on PHP 8). It documents magic hashes: inputs whose MD5 or SHA-1 digests match ^0e[0-9]+$ and are therefore parsed as 0.0 in scientific notation, making md5(a) == md5(b) true for distinct inputs such as 240610708 and QNKCDZO. Further sections cover HMAC bypasses against loose comparisons with '0', NULL juggling when invalid types like arrays produce NULL or TypeErrors, and CTF patterns using strcmp/strcasecmp with array arguments, json_decode, and intval.

Quick-start payloads and minimal php -r probes help confirm behavior, and a routing table maps each sink (== versus hash_equals, the PHP major version, whether both operands are attacker-controlled) to the relevant section. The playbook stresses fingerprinting the PHP version from headers or X-Powered-By because a payload that works on PHP 7 may fail on PHP 8, and it documents the safe defenses (hash_equals() and strict === comparison with fixed-length encoding) for verification and remediation.

FAQ

When does this skill apply?

When PHP code compares passwords, tokens, or HMAC/signature values using loose equality (==), numeric coercion, or hash comparison without strict types; if the code already uses hash_equals or ===, it usually does not apply.

What is a magic hash?

An input whose MD5 or SHA-1 digest matches ^0e[0-9]+$, which PHP interprets as 0.0 in scientific notation, so two different inputs (for example 240610708 and QNKCDZO) can make their loose (==) hash comparison return true.

Why does the skill emphasize the PHP version?

Coercion rules changed in PHP 8 (for example 0 == 'foo' is true on PHP 7 and earlier but false on PHP 8), so you must fingerprint the version from headers or X-Powered-By because a payload may work on one version and fail on another.

What are some first-pass payloads?

Values like password[]=x, an empty string, 0, 0e12345, 240610708, QNKCDZO, true, [], and a JSON body such as password set to true, used to test coercion in auth or token checks.

How can this be defended against?

Use timing-safe strict comparison with hash_equals((string)expected, (string)actual) or ===, with fixed-length hex/binary encoding, and never compare an HMAC to a bare '0'.

Install type-juggling

Download and extract the skill files to your .claude/skills/ directory.

Quick Setup:

  1. Copy the skill folder to .claude/skills/
  2. Claude will automatically detect and use the skill