Front-End JavaScript Reverse Engineering
Overview
Modern web applications move security logic (request signing, anti-bot
tokens, risk scoring) into the browser. Reversing that logic is a discipline
with its own order of operations: observing traffic first, capturing the
relevant code path, rebuilding the logic in a controlled local environment,
and only then patching or decoding. Jumping straight to breakpoints or
deobfuscation is how reversers burn hours on the wrong code.
This skill provides a five-phase workflow — Observe → Capture → Rebuild →
Patch → Decode — plus the execution discipline (evidence-first, artifact
per task, minimal patches) that keeps the process reproducible. It is
tool-agnostic: the same workflow runs on Chrome DevTools, Playwright,
puppeteer, or any CDP-capable driver, and on any runtime rebuilt in Node.js.
Source: cherry-picked and translated from zhaoxuya520/reverse-skill
(skills/js-reverse, MIT license). MCP-specific tool bindings were
generalized to standard browser/CDP tooling.
When to Use
Trigger phrases:
- "reverse the signing logic of this request"
- "how is this frontend token generated"
- "analyze obfuscated JS behavior"
- "rebuild a client-side algorithm in Node"
- "patch a JS function to verify a hypothesis"
- "deobfuscate control flow of a web SDK"
Use this skill when:
- A request carries a signature, token, or header you must reproduce or
understand (for security review, testing, or interoperability).
- Obfuscated or minified client code hides the algorithm.
- You need to confirm behavior before writing a rewrite (verify the real
runtime, never assume from source shape).
Prerequisites
- Chrome (or Chromium) with DevTools; Playwright/puppeteer if scripting.
- Node.js 18+ for local rebuilds.
- A beautifier (prettier or js-beautify) and a proficient code editor.
Workflow
Phase 1: Observe
- Open DevTools → Network, filter by the target request type; identify the
target request URL.
- Open the initiator chain / call stack of that request to find the entry
function.
- Locate the script that issues the request: find the JS file URL, then the
function name and approximate line in the Sources panel.
- Take notes on the request header names you must reproduce and their current
values.
Phase 2: Capture
- Break-on-XHR first: enable XHR breakpoints on the target URL so the
stack lands at the exact call site — the most direct capture point.
- Use light runtime observation: console-log the arguments each step of the
chain receives, not the whole call graph.
- Capture: the function name, the values in scope at the call site,
and when the computed value is added to the request.
Phase 3: Rebuild
- Rebuild the captured call chain as a local Node.js script.
- Evidence-based only: never invent
window, document, crypto, or
localStorage behavior — introduce browser globals you actually saw being
read (via the DevTools console or a strace of properties accessed).
- If the code needs a browser environment, run Playwright and evaluate the
rebuilt logic inside the page context for parity.
- Structure the script so each step prints its output: this exposes the first
divergence immediately.
Phase 4: Patch
- Apply one minimal patch per failure: on the first error or first
divergence, patch the smallest thing that resolves it, retest, log.
- Never mass-edit the target logic before it runs locally.
- Patches are for verification (fix an undefined var, seed a needed value),
not for finishing a half-rebuild.
Phase 5: Decode / DeepDive
- Only after the rebuild runs end-to-end does deobfuscation make sense:
beautify the captured scope of the algorithm and restore control flow
(switch dispatch → if/else) guided by the observed behavior.
- Extract the business logic: key derivation, signing steps, or token field
semantics.
- Downgradeable: if the task only needs the signing result (not long-term
reuse of the algorithm chain), phase 5 can stop at "locally reproduced the
value" without full control-flow recovery.
Execution Rules
- Every task produces artifacts — the script, the capture log, the patch
list. A task with no artifacts is not done.
- Final state per artifact: the runnable rebuilt script with the minimal
patches and a list of every divergence observed and its resolution.
- No unexplained tool calls: every automation action must map to a step in
this workflow.
- Fallbacks: when a capability has no implementation (e.g. deserializer
missing), fall back to the documented generic mechanism instead of
stopping.
- Evidence-first: any claim about what the code does requires a recorded
run or a captured value.
Hands-On Example
Rebuild a captured signing function in Node and confirm the digest matches
the traffic (Phase 3 — Rebuild). In a scratch directory, install the library
with npm install crypto-js, then reproduce the observed hash:
node -e "const C=require('crypto-js'); console.log(C.MD5('a=1&t=1').toString())"
# 1f16f5f46ff3c3b478e870f6446cf656
node -e "const C=require('crypto-js'); console.log(C.HmacSHA256('data','k').toString())"
# 98755ce7a0d431b5...
Verified with Node 22 + crypto-js 4.2.0 (output above). A digest match
between your rebuild and the recorded request proves you reproduced the exact
computation — the same evidence used in Phase 4 to confirm a patched script
preserves behavior.
Verification
Run this self-check before claiming completion:
When NOT to Use
- The logic is server-side only (no browser involvement) — protocol analysis
is the right tool.
- The target is real WebAssembly — use WASM tooling and
dsl-vm-reverse for
JS VM targets separately.
- The JavaScript is malware (phishing pages, droppers, exploit kits) — use
deobfuscating-javascript-malware instead; this skill targets legitimate
app signing logic, not malicious payloads.
- You only need to call the endpoint, not reproduce its algorithm — a
recorded replay may be sufficient, though context-bound tokens will break.
Anti-Rationalization Table
| Rationalization |
Reality |
| "I'll go straight to the deobfuscator." |
Deobfuscating before you have a local, running rebuild tells you nothing about what to look at. Rebuild first. |
| "I'll read the whole obfuscated file before patching." |
You only need the captured execution path. Mass-reading is slower and wrong-reasoning fodder. |
| "I invented a window object to make it run." |
Invented environment masks the real divergence and can produce a value that only appears right. |
| "The value looks plausible, so it's correct." |
Middle values are invisible; only a compared output proves correctness. |
| "One patch fixed everything." |
One error, one patch — a giant patch hides multiple divergences you will not understand later. |
1---2name: js-reverse3description: Use when front-end JavaScript reverse engineering for web apps and anti-bot engines: observe request flows, capture logic via hooks or breakpoints, rebuild in a local Node environment, apply minimal patches, and decode obfuscated signing algorithms. Use when analyzing request signing chains, obfuscated SDKs, or client-side protection logic.4license: Apache-2.05---678# Front-End JavaScript Reverse Engineering910## Overview1112Modern web applications move security logic (request signing, anti-bot13tokens, risk scoring) into the browser. Reversing that logic is a discipline14with its own order of operations: observing traffic first, capturing the15relevant code path, rebuilding the logic in a controlled local environment,16and only then patching or decoding. Jumping straight to breakpoints or17deobfuscation is how reversers burn hours on the wrong code.1819This skill provides a five-phase workflow — Observe → Capture → Rebuild →20Patch → Decode — plus the execution discipline (evidence-first, artifact21per task, minimal patches) that keeps the process reproducible. It is22tool-agnostic: the same workflow runs on Chrome DevTools, Playwright,23puppeteer, or any CDP-capable driver, and on any runtime rebuilt in Node.js.2425Source: cherry-picked and translated from `zhaoxuya520/reverse-skill`26(`skills/js-reverse`, MIT license). MCP-specific tool bindings were27generalized to standard browser/CDP tooling.2829## When to Use3031**Trigger phrases:**32- "reverse the signing logic of this request"33- "how is this frontend token generated"34- "analyze obfuscated JS behavior"35- "rebuild a client-side algorithm in Node"36- "patch a JS function to verify a hypothesis"37- "deobfuscate control flow of a web SDK"3839Use this skill when:4041- A request carries a signature, token, or header you must reproduce or42 understand (for security review, testing, or interoperability).43- Obfuscated or minified client code hides the algorithm.44- You need to confirm behavior before writing a rewrite (verify the real45 runtime, never assume from source shape).4647## Prerequisites4849- Chrome (or Chromium) with DevTools; Playwright/puppeteer if scripting.50- Node.js 18+ for local rebuilds.51- A beautifier (prettier or js-beautify) and a proficient code editor.5253## Workflow5455### Phase 1: Observe5657- Open DevTools → Network, filter by the target request type; identify the58 target request URL.59- Open the initiator chain / call stack of that request to find the entry60 function.61- Locate the script that issues the request: find the JS file URL, then the62 function name and approximate line in the Sources panel.63- Take notes on the request header names you must reproduce and their current64 values.6566### Phase 2: Capture6768- **Break-on-XHR first**: enable XHR breakpoints on the target URL so the69 stack lands at the exact call site — the most direct capture point.70- Use light runtime observation: console-log the arguments each step of the71 chain receives, not the whole call graph.72- Capture: the function name, the values in scope at the call site,73 and when the computed value is added to the request.7475### Phase 3: Rebuild7677- Rebuild the captured call chain as a local Node.js script.78- Evidence-based only: never invent `window`, `document`, `crypto`, or79 `localStorage` behavior — introduce browser globals you actually saw being80 read (via the DevTools console or a strace of properties accessed).81- If the code needs a browser environment, run Playwright and evaluate the82 rebuilt logic inside the page context for parity.83- Structure the script so each step prints its output: this exposes the first84 divergence immediately.8586### Phase 4: Patch8788- Apply **one minimal patch per failure**: on the first error or first89 divergence, patch the smallest thing that resolves it, retest, log.90- Never mass-edit the target logic before it runs locally.91- Patches are for verification (fix an undefined var, seed a needed value),92 not for finishing a half-rebuild.9394### Phase 5: Decode / DeepDive9596- Only after the rebuild runs end-to-end does deobfuscation make sense:97 beautify the captured scope of the algorithm and restore control flow98 (switch dispatch → if/else) guided by the observed behavior.99- Extract the business logic: key derivation, signing steps, or token field100 semantics.101- **Downgradeable**: if the task only needs the signing result (not long-term102 reuse of the algorithm chain), phase 5 can stop at "locally reproduced the103 value" without full control-flow recovery.104105## Execution Rules106107- Every task produces artifacts — the script, the capture log, the patch108 list. A task with no artifacts is not done.109- Final state per artifact: the runnable rebuilt script with the minimal110 patches and a list of every divergence observed and its resolution.111- No unexplained tool calls: every automation action must map to a step in112 this workflow.113- Fallbacks: when a capability has no implementation (e.g. deserializer114 missing), fall back to the documented generic mechanism instead of115 stopping.116- Evidence-first: any claim about what the code does requires a recorded117 run or a captured value.118119## Hands-On Example120121Rebuild a captured signing function in Node and confirm the digest matches122the traffic (Phase 3 — Rebuild). In a scratch directory, install the library123with `npm install crypto-js`, then reproduce the observed hash:124125```bash126node -e "const C=require('crypto-js'); console.log(C.MD5('a=1&t=1').toString())"127# 1f16f5f46ff3c3b478e870f6446cf656128129node -e "const C=require('crypto-js'); console.log(C.HmacSHA256('data','k').toString())"130# 98755ce7a0d431b5...131```132133Verified with Node 22 + crypto-js 4.2.0 (output above). A digest match134between your rebuild and the recorded request proves you reproduced the exact135computation — the same evidence used in Phase 4 to confirm a patched script136preserves behavior.137138## Verification139140Run this self-check before claiming completion:141142- [ ] Target request URL and initiator chain are documented.143- [ ] Break-on-XHR or equivalent capture produced the full function chain144 with observed values.145- [ ] The rebuilt Node/Playwright script reproduces the target value without146 invented browser behavior.147- [ ] Each patch is minimal, logged, and justified (one error → one patch).148- [ ] The final value is compared live against a real page capture and149 matches.150- [ ] If the task needed control-flow recovery: the deobfuscated version151 recompiles/reruns and produces the same output.152153## When NOT to Use154155- The logic is server-side only (no browser involvement) — protocol analysis156 is the right tool.157- The target is real WebAssembly — use WASM tooling and `dsl-vm-reverse` for158 JS VM targets separately.159- The JavaScript is malware (phishing pages, droppers, exploit kits) — use160 `deobfuscating-javascript-malware` instead; this skill targets legitimate161 app signing logic, not malicious payloads.162- You only need to call the endpoint, not reproduce its algorithm — a163 recorded replay may be sufficient, though context-bound tokens will break.164165## Anti-Rationalization Table166167| Rationalization | Reality |168|---|---|169| "I'll go straight to the deobfuscator." | Deobfuscating before you have a local, running rebuild tells you nothing about what to look at. Rebuild first. |170| "I'll read the whole obfuscated file before patching." | You only need the captured execution path. Mass-reading is slower and wrong-reasoning fodder. |171| "I invented a window object to make it run." | Invented environment masks the real divergence and can produce a value that only appears right. |172| "The value looks plausible, so it's correct." | Middle values are invisible; only a compared output proves correctness. |173| "One patch fixed everything." | One error, one patch — a giant patch hides multiple divergences you will not understand later. |