A full-featured JavaScript deobfuscator powered by AST transforms and LLM-assisted analysis.
cascade-js reverses JavaScript obfuscation, targeting patterns generated by javascript-obfuscator and similar tools. It combines pure AST-based transformations with optional LLM-assisted analysis for complex prelude detection. The LLM is optional, many passes work entirely via AST analysis without any API calls.
cascade-js includes 19 transformation passes organized into five categories:
| Pass | Description |
|---|---|
| string-array | Pure AST detection of string array patterns with fallback to LLM-assisted analysis for complex variants |
| string-array-sandbox | Safe execution of string array rotation functions using QuickJS WASM sandbox |
| string-array-replace | Replaces encoded string accesses with decoded literal values |
| Pass | Description |
|---|---|
| self-defending | Removes self-defending wrappers that prevent code formatting |
| debug-protection | Strips debugger detection and infinite loops designed to thwart debugging |
| console-output | Removes console output tampering and redirection |
| domain-lock | Eliminates domain and URL-based restrictions |
| Pass | Description |
|---|---|
| control-flow-flattening | Restores flattened control flow from switch-based and object-based CFF patterns |
| dead-code-removal | Eliminates injected dead code blocks that never execute |
| object-keys | Converts computed object keys back to literal property names |
| split-strings | Concatenates split string literals into single strings |
| unicode-escape | Converts Unicode escape sequences to readable characters |
| numbers-to-expressions | Evaluates numeric expressions back to literal values |
| Pass | Description |
|---|---|
| string-replacement | Propagates decoded string literals throughout the code |
| constant-propagation | Evaluates and propagates constant expressions at compile time |
| function-inlining | Inlines simple functions to reduce indirection |
| Pass | Description |
|---|---|
| boolean-literals | Normalizes boolean literal expressions to true/false |
| cleanup | Removes unused variables, dead branches, and empty functions |
| unminify | Applies 16 sub-transforms to restore readable formatting: brace spacing, semicolon insertion, quote normalization, indentation, and more |
npm install cascade-jspnpm add cascade-jsFor global CLI access:
npm install -g cascade-jsRequirements: Node.js >= 18 (ES2022 target)
# Basic usage
cascade-js input.js output.js
# Read from stdin, write to stdout
cat obfuscated.js | cascade-js - -
# Specify LLM provider
cascade-js input.js output.js --provider openai --model gpt-4o-mini
# JSON output for programmatic use
cascade-js input.js --jsonimport { deobfuscate } from 'cascade-js';
const obfuscated = `
var _0x1234 = ['Hello', 'World'];
function _0x5678(n) { return _0x1234[n]; }
console.log(_0x5678(0) + ' ' + _0x5678(1));
`;
const result = await deobfuscate(obfuscated);
console.log(result.code);
// console.log('Hello World');The CLI provides a convenient way to deobfuscate files from the command line. For complete documentation, see docs/cli.md.
cascade-js [input] [output] [options]Arguments:
input- Input file path (use-for stdin)output- Output file path (use-for stdout, omit to print to stdout)
Options:
--provider <name>- LLM provider: openai, anthropic, gemini, ollama (default: openai)--model <model>- Model name (provider-specific default)--api-key <key>- API key (falls back to CASCADE_API_KEY env var)--base-url <url>- Custom API base URL for compatible providers--timeout <ms>- Timeout in milliseconds (default: 60000)--verbose- Enable verbose logging--quiet- Suppress all output except result--no-prefilter- Skip obfuscation detection, process all input--json- Output results as JSON
Examples:
# Basic file processing
cascade-js obfuscated.js cleaned.js
# Stdin/stdout piping
curl -s https://example.com/script.js | cascade-js - - > cleaned.js
# Using Anthropic with custom timeout
cascade-js input.js output.js --provider anthropic --timeout 120000
# JSON output for scripting
cascade-js input.js --json | jq '.code'The API provides programmatic access to the deobfuscation engine. For complete documentation, see docs/api.md.
import { deobfuscate } from 'cascade-js';
const result = await deobfuscate(obfuscatedCode);
console.log(result.code); // Deobfuscated code
console.log(result.warnings); // Any warnings generated
console.log(result.stats); // Processing statisticsimport { createPipeline, stringArrayPass, controlFlowFlatteningPass, unminifyPass } from 'cascade-js';
const pipeline = createPipeline({
options: { timeout: 120000 },
passes: [stringArrayPass, controlFlowFlatteningPass, unminifyPass]
});
const result = await pipeline.run(code);import { deobfuscate, definePass } from 'cascade-js';
const myPass = definePass({
name: 'my-custom-pass',
dependencies: ['string-replacement'],
async transform(code, context) {
// Your transformation logic
return transformedCode;
}
});
const result = await deobfuscate(code, {
customPasses: [myPass]
});cascade-js targets patterns generated by popular obfuscation tools. This table maps javascript-obfuscator options to cascade-js passes:
| javascript-obfuscator Option | cascade-js Pass(es) |
|---|---|
stringArray |
string-array, string-array-sandbox, string-array-replace |
stringArrayRotate |
string-array-sandbox |
stringArrayShuffle |
string-array-sandbox |
controlFlowFlattening |
control-flow-flattening |
deadCodeInjection |
dead-code-removal |
debugProtection |
debug-protection |
selfDefending |
self-defending |
disableConsoleOutput |
console-output |
domainLock |
domain-lock |
splitStrings |
split-strings |
unicodeEscapeSequence |
unicode-escape |
numbersToExpressions |
numbers-to-expressions |
transformObjectKeys |
object-keys |
simplify |
constant-propagation, function-inlining |
cascade-js uses a multi-stage pipeline architecture:
Input: Obfuscated JavaScript
|
v
+--------------+
| Prefilter | --> Quick heuristic detection of obfuscation patterns
+--------------+
|
v
+--------------+
|Prelude Detect| --> LLM-assisted or pure-AST identification of string arrays,
+--------------+ rotation functions, and fetcher functions
|
v
+--------------+
| Sandbox | --> Safe execution in QuickJS WASM to extract decoded strings
+--------------+
|
v
+--------------+
|Pass Pipeline | --> Topological sort on pass dependencies, then sequential
+--------------+ application of AST transformations
|
v
Output: Deobfuscated JavaScript
Key Components:
-
Prefilter - Pattern-based detection using hex identifier counting, string array matching, and confidence scoring
-
Prelude Detection - Identifies obfuscation prelude structures (string arrays, fetchers, rotators) using either pure AST analysis or LLM-assisted parsing
-
Sandbox - QuickJS-emscripten isolation for safe execution of untrusted rotation functions without affecting the host environment
-
Pipeline - Dependency-resolving pass executor that runs transformations in topological order based on declared dependencies
cascade-js supports multiple LLM providers for complex prelude detection. The LLM is optional and only used when pure AST detection fails to identify obfuscation patterns.
| Provider | Default Model | Environment Variable | Config Options |
|---|---|---|---|
| OpenAI | gpt-4o-mini | OPENAI_API_KEY |
model, baseURL |
| Anthropic | claude-3-haiku-20240307 | ANTHROPIC_API_KEY |
model, baseURL |
| Gemini | gemini-1.5-flash | GOOGLE_API_KEY |
model, baseURL |
| Ollama | llama3.2 | None (local) | model, host |
Global API Key:
You can also set CASCADE_API_KEY as a fallback for any provider.
Example Configuration:
import { deobfuscate, OpenAILLMAdapter } from 'cascade-js';
// Using environment variable
const result = await deobfuscate(code);
// Explicit adapter configuration
const result = await deobfuscate(code, {
llmAdapter: new OpenAILLMAdapter(process.env.OPENAI_API_KEY, 'gpt-4o')
});
// Using Anthropic
import { AnthropicLLMAdapter } from 'cascade-js';
const result = await deobfuscate(code, {
llmAdapter: new AnthropicLLMAdapter(process.env.ANTHROPIC_API_KEY)
});Contributions are welcome. See docs/contributing.md for guidelines on setting up the development environment, running tests, and submitting pull requests.
Quick start for contributors:
git clone https://github.com/yourusername/cascade-js.git
cd cascade-js
pnpm install
pnpm build
pnpm testMIT License - see LICENSE for details.