A small, practical JavaScript obfuscator that sits between basic string mangling and full VM-based obfuscation. It uses a tiny custom VM for strings, then hands off to javascript-obfuscator for the heavy lifting.
Make sure your project is using ES modules ("type": "module" in package.json) or run with a Node version/config that supports import.
Built for production use where full virtual machines are too slow and standard obfuscation is too easy to peel apart.
-
~150 lines of ES module code
-
Custom string-decoding VM with 2 opcodes
- XOR decode
- Fixed offset shift
-
Random XOR key per build (1–255)
-
Per-character randomized opcode selection
-
Two-stage pipeline:
- Babel plugin (AST transform)
javascript-obfuscatorpass
-
~1.2× runtime overhead in practice (compared to ~3–5× for full VM obfuscators)
This is not meant to be unbreakable. It’s meant to be annoying enough that reversing isn’t trivial, without killing performance.
-
Full VM obfuscation is usually too slow for real-world production code
-
Standard obfuscation is often too easy to pattern-match and undo
-
This aims for the middle ground:
- Custom logic that breaks tooling assumptions
- Low overhead
- Simple enough to reason about and maintain
- Babel – AST transforms and string replacement
- javascript-obfuscator – control flow flattening, dead code, renaming, etc.
- Node.js
- ES modules
npm installDependencies you’ll need:
npm install @babel/core javascript-obfuscatorNode 16+ recommended.
node obfuscator.js input.js output.jsWhat happens:
- Generates a random XOR key for the build
- Replaces eligible string literals with VM bytecode
- Injects a tiny VM decoder function
- Runs
javascript-obfuscatorwith a custom dictionary and control-flow options - Writes the final obfuscated output
-
During the Babel pass:
-
String literals (above a minimum length and not common DOM words) are replaced
-
Each character is encoded as:
[1, char ^ xorKey]or[2, char + 5]
-
Opcode choice is randomized per character
-
-
A small VM function is injected:
- Iterates bytecode
- Decodes characters based on opcode
- Reconstructs the string at runtime
-
The output is then passed through
javascript-obfuscatorto:- Flatten control flow
- Inject dead code
- Rename identifiers using a fixed dictionary
- Add additional noise around the VM logic
The VM is intentionally minimal to keep runtime cost low.