egodeath
This project does not achieve indistinguishability obfuscation. You should not be using this to product to protect secrets. It exists to deter reverse engineering, not prevent it

A JavaScript obfuscator designed to make code extremely difficult to read and analyze for both humans and LLMs. Written in TypeScript. Implements techniques from peer-reviewed cryptographic obfuscation research.
Installation
npm install
npm run build
CLI Usage
# Basic usage
node dist/index.js input.js > output.js
# With target token budget (default: 2,000,000)
node dist/index.js --target-tokens 500000 input.js > output.js
# Minimal obfuscation (small output)
node dist/index.js --target-tokens 10000 input.js > output.js
# Maximum bloat (10M tokens)
node dist/index.js --target-tokens 10000000 input.js > output.js
# Using environment variable
INPUT_FILE=input.js node dist/index.js > output.js
# Help
node dist/index.js --help
Options
| Option | Default | Description |
|---|
--target-tokens <n> | 2000000 | Target output size in tokens. Small inputs are bloated up to this limit. Large inputs produce less bloat to stay within budget. |
--help, -h | | Show help message |
npm scripts
npm run build # Compile TypeScript to dist/
npm run start # Run the obfuscator (reads input.js)
npm run test # Run the test suite
npm run obfuscate-package # Run compatibility tests against npm packages
Programmatic API
const { obfuscate } = require('./dist/obfuscator');
const code = 'function add(a, b) { return a + b; }';
const obfuscated = obfuscate(code);
// With options
const obfuscated = obfuscate(code, { targetTokens: 500000 });
The obfuscator applies 20 transforms across 4 phases. Each stage builds on the previous one.
Phase 3: Identifier Passes
Phase 4: Post-transforms
Dead Code Injection
Dead code is injected at multiple points with two generation strategies:
| Strategy | Source | Description |
|---|
|
Dead code injection points:
- CFF dead switch cases (~30% extra per function, scaled by budget)
- Opaque predicate else branches
- Standalone dead blocks in non-CFF functions (budget-controlled)
Research Paper References
Several transforms are inspired by peer-reviewed cryptographic obfuscation research:
Two verification tools measure obfuscation quality, located in src/verification/:
Null Circuit Test (verification/nullCircuitTest.ts)
Obfuscates a real function and a "null" function (same shape, does nothing), then compares 14 structural metrics to score how distinguishable they are. Higher similarity = better obfuscation.
import { runNullCircuitTest } from './verification/nullCircuitTest';
const result = runNullCircuitTest(realCode, paramCount, stmtCount, threshold, targetTokens);
console.log('Similarity:', result.similarity); // 0.0-1.0
Unobfuscatable Function Tests (verification/unobfuscatableTests.ts)
7 test cases from Paper 1's impossibility proofs that attempt to extract secrets from obfuscated code:
import { runAllTests, printSummary } from './verification/unobfuscatableTests';
console.log(printSummary(runAllTests(10000)));
Tests: point function (password), magic numbers, canary strings, embedded keys, URLs, regex patterns, control flow signatures.
Output Size Budget
The --target-tokens option controls output size via a bloat budget that scales dead code injection (the primary volume lever). Budget-gated transforms:
| Budget Ratio | Transforms Enabled |
|---|
| > 3 | Anti-debug, tripwires, CFF, opaque predicates, comma merging |
| > 5 | Proxy functions, property key encoding, noise injection, self-integrity |
| > 8 | Context window exhaustion |
| > 10 | Global variable encoding |
Dead code multiplier scales from 1x (ratio 30) to 150x (ratio 1500+), controlling the number and size of dead switch cases and opaque predicate branches.
Project Structure
src/
index.ts CLI entry point
obfuscator.ts Main pipeline orchestrator (20 transforms)
options.ts Budget system and options
types.ts AST type definitions
random.ts Random Unicode name generation (6-16 chars, 16 script ranges)
ast.ts AST node factory functions
keywords.ts Dynamic keyword discovery (globalThis + window package)
globals.ts Global state management (null-prototype maps)
substitute.ts Identifier substitution utilities
declarations.d.ts Module type declarations
passes/
firstPass.ts Identifier cataloging
secondPass.ts Identifier substitution + string encoding
thirdPass.ts Dummy parameter injection
transforms/
antiDebug.ts eval("debugger") traps + setInterval loops
tripwires.ts Punctured program secret-input checks [Paper 4]
noiseInjection.ts LPN-inspired arithmetic noise [Paper 7]
controlFlowFlattening.ts while/switch + modular arithmetic dispatch [Paper 3]
opaquePredicates.ts 15 always-true/false math predicates
proxyFunctions.ts Call graph flattening dispatchers
contextExhaustion.ts Ternary/void noise for LLM context filling
commaExpressions.ts Statement merging via comma operator
globalVariableEncoding.ts eval+replace for globals
propertyKeyEncoding.ts Computed property access with per-scope registries
numberEncoding.ts 11 bitwise/arithmetic encoding strategies
selfIntegrity.ts Anti-tamper runtime checks [Paper 10]
stringArrayExtraction.ts Chained XOR + sparse position errors [Papers 2, 9]
deadCodeInjection.ts Template + mutation-based dead code [Paper 3]
verification/
nullCircuitTest.ts Dead code quality scoring [Paper 10]
unobfuscatableTests.ts Secret extraction test cases [Paper 1]
__tests__/ 300+ unit tests across 21 suites
tools/
obfuscate-package.ts Webpack-based npm package compatibility testing
tests/
input*.js Original test input files
Testing
# Run all tests
npm test
# Run a specific test suite
npx jest controlFlowFlattening
npx jest tripwires
npx jest noiseInjection
# Test against npm packages (clones repos, webpack-bundles, obfuscates, runs tests)
npm run obfuscate-package # All 10 packages
npm run obfuscate-package -- minimist semver # Specific packages
The tools/obfuscate-package.ts tool tests the obfuscator against real npm packages:
- Clones the package's git repository
- Installs all dependencies (including devDependencies for testing)
- Builds the package if it has a build script
- Uses webpack to bundle the library's main entry point into a single CommonJS file
- Runs the obfuscator on the bundled file
- Replaces the library's main entry with the obfuscated bundle
- Runs the library's own test suite against the obfuscated version
Output locations
| Path | Contents |
|---|
dist/obfuscated/<package>/bundle.js | The obfuscated webpack bundle for each package |
dist/obfuscated/report.json | Full JSON report with bundle sizes, obfuscation status, test output |
License
MIT - Copyright 2026 Nicholas Starke