JSIMPLIFIER: Scalable JS Deobfuscation
- JSIMPLIFIER is a multi-stage deobfuscation framework that transforms obfuscated JavaScript into human-readable code using fault-tolerant parsing, hybrid static-dynamic analysis, and LLM-based identifier renaming.
- It employs a structured pipeline that includes preprocessing for normalization, in-depth AST analysis with static and sandboxed dynamic execution, and beautification via LLMs and code formatters.
- Empirical evaluations demonstrate high semantic consistency, significant reductions in code complexity, and robust performance across a broad spectrum of obfuscation techniques.
JSIMPLIFIER is a comprehensive, multi-stage deobfuscation framework designed for robust, scalable security analysis of JavaScript code exhibiting a wide range of obfuscation techniques. Its architecture addresses the limitations of prior tools by integrating fault-tolerant parsing, static and dynamic analysis, and LLM-based identifier renaming, thereby enabling the reliable transformation of cryptic, obfuscated code into human-readable form, with empirical validation on the largest real-world JavaScript obfuscation dataset to date (Zhou et al., 16 Dec 2025).
1. System Architecture
JSIMPLIFIER operationalizes deobfuscation as a linear three-stage pipeline, designed to process malformed or malicious JavaScript into semantically equivalent, human-readable code. The workflow consists of:
- Stage 1: Preprocessor Ensures lexical and semantic validity using Meriyah-based parsing, escape-sequence normalization, semantic legacy-to-strict conversion, scope-chain correction, redundant declaration elimination, and unpacks module bundlers (webpack/browserify).
- Stage 2: Deobfuscator
Applies static Abstract Syntax Tree (AST) analysis using multi-parser fallback (Esprima → Acorn → Babel), pattern-based code rewrites, binary/logical expression evaluation, destructuring, and scope tracking. Unresolved constructs are analyzed via dynamic execution in a sandboxed Node.js
vmcontext, with feedback loops to update the AST. Hybrid coordination facilitates the safe transfer of unhandled nodes between static and dynamic analysis. - Stage 3: Humanizer Deploys LLMs (GPT, Gemini, Claude) for identifier renaming with semantic context validation, followed by code beautification using Prettier.
The pipeline ensures end-to-end compatibility and correctness across diverse obfuscation techniques and input formats.
2. Component Methodologies and Key Algorithms
2.1 Preprocessor
The preprocessor normalizes arbitrarily malformed, legacy, or bundled JavaScript into an AST suitable for subsequent analysis. Key methodologies include:
- Fault-Tolerant Parsing:
Utilizes Meriyah for recovery from syntax errors, producing a partial or complete AST.
- Lexical Sanitization:
Converts hexadecimal and octal escapes to standard Unicode and UTF-8, as illustrated in the normalization pseudocode:
1 2 3 4 |
for each token in AST: if token matches /\x([0-9A-Fa-f]{2})/ or octal escape: normalize to \xHH // Reassemble \xHH sequences, decode as UTF-8, replace with \uXXXX |
- Semantic Compatilization:
Translates legacy constructs (e.g., /*@cc_on...@*/) to standards-compliant code, adds missing var/let, and cleans invalid operations such as deleting identifiers.
- Structural Refinement:
Resolves redeclaration and identifier shadowing via scope-chain traversal, undertaking safe renames or merges.
- Bundler Unpack:
Automatically unwraps webpack/browserify constructs, inlining module arrays and substituting synthetic imports.
2.2 Deobfuscator
- Static AST Analysis:
Multi-parser fallback attempts several parsers in sequence for maximal resilience. Enhanced evaluators compute constant expressions and handle complex desctructuring. Indirect call resolution and scope chain management ensure semantic fidelity.
Example pseudocode for expression evaluation:
1 2 3 4 5 6 7 8 9 10 11 |
function evalExpression(node): switch node.type: case Literal: return node.value case BinaryExpression: return applyOperator(node.operator, evalExpression(node.left), evalExpression(node.right)) case LogicalExpression: left = evalExpression(node.left) if node.operator == '||' and left truthy: return left if node.operator == '&&' and !left: return left return evalExpression(node.right) |
- Dynamic Execution Tracing:
Pre-execution risk assessment scans for potentially malicious patterns (e.g., eval, infinite loops). Code fragments are executed in a sandbox with controlled timeouts and stubs for unsafe globals. If execution yields literals, function bodies, or strings, these are reinserted into the AST, which is then re-analyzed.
- Hybrid Static-Dynamic Coordination:
Nodes not statically analyzable are queued for dynamic analysis; conversely, dynamic results are merged, splicing in AST fragments or collapsing subtrees to primitives.
2.3 Humanizer
- LLM-Enhanced Identifier Renaming:
For each identifier, semantic and syntactic context are assembled and passed to multiple LLMs for renaming suggestions, validated to avoid scope conflicts before accepting changes.
- Beautification:
Source is formatted according to canonical JavaScript styling rules using Prettier.
3. Multi-Dimensional Evaluation Metrics
JSIMPLIFIER introduces and operationalizes multiple orthogonal metrics for benchmarking deobfuscation efficacy:
- Control/Data-Flow Similarity:
Given original and deobfuscated program graphs , similarity is
where MCS denotes Maximum Common Subgraph cardinality. For graphs exceeding 40 nodes, approximations by node and edge counts are used.
- Code Simplification (Halstead):
Code complexity reduction measured by
with analogous effort reduction HER.
- Entropy Analysis:
Code-text entropy is
AST entropy is formulated as a weighted sum:
with calibrated weights .
- LLM-Based Readability:
For LLM scores ,
4. Dataset Construction and Composition
JSIMPLIFIER is validated on a comprehensive corpus totaling 44,421 samples, split as:
- MalJS: 23,212 malicious samples, collected (2019–2025), filtered for syntax validity by Meriyah, deduplicated, and stratified by a four-point obfuscation scoring scheme encompassing lexical, syntactic, semantic, and multi-layer factors.
- BenignJS: 21,209 benign samples from high-traffic Tranco domains, with 2,000 manually validated clean samples from open-source (GitHub) and PublicWWW corpus. Additionally, for correctness/semantic tests, 500 samples were artificially re-obfuscated across categories.
- CombiBench: 1,296 multi-technique combination samples drawn from JsDeObsBench.
Dataset stratification enables evaluation over technique coverage (20 variants), correctness and control/data-flow preservation (manually annotated subsets), code simplification (CombiBench), and entropy/readability (full dataset).
5. Empirical Results
Quantitative evaluation across standard and novel metrics demonstrates the following:
- Technique Coverage:
JSIMPLIFIER processes all 20 tested obfuscation techniques (20/20), compared to baselines achieving 14–19/20.
- Correctness & Semantic Consistency:
For 400 evaluation samples, parsing and correctness rates are 100%. Control Flow Graph similarity averages 93.78%, Data Dependence Graph preservation 95.84%, and semantic consistency 83% (vs GPT: 74%, JST: 55%).
- Code Complexity/Simplification:
Halstead Length Reduction (HLR) is 0.8820 (88.2%), and Halstead Effort Reduction (HER) is 0.9291. Baselines: SYN HLR 0.7889, SDS HLR 0.0015.
- Entropy and Readability:
JSIMPLIFIER achieves 100% coverage versus JST (67.9%) and ILL (31.8%). Both median code and AST entropy drop substantially post-deobfuscation. LLM-based readability improvement for 60 code pairs ranges from +243.1% (GPT-o3) to +618.6% (Gemini 2.5).
- Performance:
For the full MalJS corpus (23K samples), JSIMPLIFIER achieves 100% success, mean runtime 0.0036 s/sample, and negligible memory overhead. Comparisons: JST (22.69 s, 45.7% success), ILL (6.26 s, 19.1% success).
6. Limitations, Failure Modes, and Future Directions
Key implementation challenges include parsing severely malformed inputs (solved via multi-parser fallback), balancing static versus dynamic evaluation (addressed with sandboxing and risk heuristics), and managing AST integrity during dynamic result splicing. LLM-related constraints encompass cost, latency, and hallucination. Observed failure modes include:
- LLM-generated renaming hallucinations (12% of cases), resulting in undefined variables or excessive verbosity.
- Occasional semantic drift due to insufficient emulated context during dynamic tracing.
- Resistance to “time-bomb” loop constructs, requiring deeper static analysis to prevent analysis hang.
Anticipated future work includes adversarially robust obfuscation benchmarks, integration of symbolic execution to minimize sandboxing, support for new ECMAScript features, on-premises LLM fine-tuning for renaming, and hardware/containerized sandboxing to eliminate VM-escape vulnerabilities (Zhou et al., 16 Dec 2025).