shuvonsec/claude-bug-bounty/client-reverse
Claude Code and agent skill by shuvonsec/claude-bug-bounty
- community
Checking that the SKILL.md file is still in the repository.
Client-side request-signing and anti-bot token reversal for bug bounty — when a request carries a sign/sig/hmac/token/nonce/timestamp/X-Sensor header that Burp Repeater cannot replay, recover the signer just enough to reproduce the request outside the client. Packet-first staging (capture real request → prove replay works → only reverse if replay fails) across the locate→recover→runtime→validation→replay spine. Covers tracing backward from the signature field (writer→builder→entry→source), isolating user-mutable sign inputs (timestamp/nonce/deviceId/body) vs constants (secret key), hooking fetch/XHR in DevTools, JS deobfuscation basics (webpack/wasm/JSVMP), and the bounty payoff: reach the protected API to then hunt IDOR/auth/business-logic. Use when Burp/mitmproxy replay of a signed or anti-bot-gated request fails and you suspect a client-computed field is blocking you.
Install
npx vskill@latest install shuvonsec/claude-bug-bounty/client-reverseSKILL.md
CLIENT-SIDE REQUEST-SIGNING / ANTI-BOT TOKEN REVERSAL
You hit a request you cannot replay. Burp Repeater returns 401 invalid signature or 403 bot detected even though the browser/app does it fine. There is a sign, sig, X-Signature, _token, nonce, X-Acf-Sensor-Data, or encrypted body the client computes. This skill recovers just enough of that signer to reproduce the request outside the client.
Why a bug bounty hunter cares: the signature is not the bug. The signature is the lock on the door. Behind it is an API the program assumed only their own client would ever reach — so that API is often under-tested for IDOR, BOLA, mass assignment, and business logic. Reversing the signer is the cost of admission; the payout comes from what you fuzz once you're inside. Never report "I reversed your sign algorithm" as a finding on its own — that is N/A. Report the IDOR/auth bug you reached through it.
THE CORE PRINCIPLE: PACKET-FIRST
Reverse engineering is a blocker-resolution step, not the default entrypoint. Capture the real request first. Prove whether it already replays. Only reverse the signer if replay actually fails.
Most hunters waste hours decompiling JS for a "signature" that turns out to be replayable as-is, or gated by a timestamp that's valid for 5 minutes. Run this gate before opening DevTools Sources:
Steps 2–4 alone kill ~half of "I need to reverse this" assumptions. A signature that omits the payload or endpoint, or never expires, is itself the bug — see the CoinMate pattern in Real Paid Examples.
STAGE SPINE: locate → recover → runtime → validation → replay
Pick the stage from engineering state, not from clue words. "I see the word sign" does not mean you're in recover. You are in locate until you can point at the exact line that writes the signature.
| Stage | Enter when... | Goal | Exit when... | |
|---|---|---|---|---|
| locate | the signing function / write boundary is unproven | find where the sign field is written and what feeds it | you can point at writer ← builder ← entry ← source | |
| recover | boundary is real but the code is obfuscated/opaque | de-shell only the layer blocking you (webpack/wasm/JSVMP) | you have a readable or callable signer contract | |
| runtime | code is clear but browser-exec ≠ your-exec diverge | find the first divergence (missing object/state/anti-debug) | local run reproduces browser sign output | |
| validation | remaining work is equivalence proof | match checkpoints, not just final output | sign(input) == observed for fresh inputs | |
| replay | sign reproduces outside the client | Burp/Python baseline request you can fuzz | a stable request you can mutate for IDOR/auth |
Carry a one-line handoff between stages. Do not promote a guess to a fact:
STAGE 1 — LOCATE: trace backward from the signature field
You know the output (the sign value on the wire). Walk backward to the source. Keep each layer distinct:
- writer — the line that finally puts
signinto the body/header/query/cookie/WS frame - builder — the transform:
HMAC,MD5,AES, sort-then-concat,JSON.stringifyordering - entry — the UI action / callback / response that kicks off the chain
- source — what feeds the inputs: upstream response, localStorage, cookie,
Date.now(),crypto.getRandomValues, user input
Browser: find the writer in Chrome DevTools
Strong first observation points (where to put the breakpoint)
| Sink (where sign lands) | First place to prove | |
|---|---|---|
| request body field | final JSON.stringify / submit / fetch(body=...) | |
| request header | the headers[...] = or setRequestHeader call | |
| JS-set cookie | the document.cookie = setter | |
| WebSocket frame | the final envelope object right before ws.send(...) | |
anti-bot blob (X-Sensor-Data, _px) | the SDK init() and the getter that returns the blob |
Do NOT broad-deobfuscate before the boundary is real. Keyword hits are not proof — many bundles ship sign strings that never run.
STAGE 2 — RECOVER: de-shell only what blocks you
Enter only after the boundary is proven and the only remaining blocker is that the code is unreadable. Reduce the single layer in your way — never the whole bundle.
| Shell you hit | What it means | Minimal move | |
|---|---|---|---|
| webpack bootstrap | modules wrapped in __webpack_require__ | break inside the target module, read the local closure — don't unpack the whole bundle | |
| string-array obfuscation | _0x4a2b[12] lookups | in console, print the decoder array; or set a breakpoint and read decoded values live | |
worker / postMessage bridge | sign runs in a Web Worker | breakpoint the worker script; treat postMessage payload as the contract | |
| wasm loader | sign math compiled to wasm | hook the JS↔wasm boundary; capture inputs/outputs rather than decompiling wasm | |
| JSVMP (custom bytecode VM) | a dispatcher loop interpreting bytes | do not reverse the VM — go runtime: hook inputs+output and treat sign as a black box |
The black-box shortcut beats decompilation 90% of the time. You almost never need to understand the HMAC math. You need the input tuple and a way to call the function. Capturesign(input) → outputpairs at runtime; if you can call the page's own signer, you never have to reimplement it.
Reimplement vs reuse the page's signer
STAGE 3 — ISOLATE THE INPUTS (the part that decides if replay is even possible)
For every input to the signer, classify it. This is the whole game — it tells you what you can mutate and whether you even need the secret.
| Input | Type | Attacker-mutable? | Implication | |
|---|---|---|---|---|
timestamp / ts | per-request | yes (you set it) | fine — regenerate per replay; check the validity window | |
nonce / requestId | per-request random | yes | fine — generate fresh; check if server enforces uniqueness (replay protection) | |
deviceId / uuid | per-session | yes (one value, reusable) | grab once, pin it — usually constant for your session | |
| request body / path | per-request | yes | the prize — if sign covers it, you mutate body + re-sign to fuzz IDOR/mass-assignment | |
secret key / appSecret | constant, baked in | no (you extract it) | if it's in the JS bundle / APK, extraction = full forge ability for any request |
Hunt the bundle for a baked secret before doing anything clever:
STAGE 4 — RUNTIME & VALIDATION: prove your sign == the app's sign
If you reimplemented the signer in Python, prove equivalence on a fresh input before trusting it. Compare checkpoints, not just the final byte:
The two killers are almost always (a) JSON key ordering / separator whitespace, and (b) concatenation order of the input fields. If your digest is wrong, diff the pre-hash message string against the one the app builds (log it at a breakpoint), not the output hash.
STAGE 5 — REPLAY: build the request you'll actually fuzz
You are ready only when you can answer all five:
Then drive it from Python so you can fuzz at scale:
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/client-reverse/SKILL.md
Popularity
- Repository stars
- 4,237
- Repository forks
- 768
- 7-day trend score
- 42
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/shuvonsec/claude-bug-bounty/client-reverse)