VM Obfuscation

What is VM Obfuscation?

Highest Security

VM obfuscation is the most advanced form of code protection. It transforms your JavaScript functions into custom bytecode that runs on a virtual machine embedded in the output. The original logic is completely hidden — no JavaScript to reverse-engineer.

Targeting Specific Functions

Recommended

For optimal performance, VM-obfuscate only your most sensitive code using vmTargetFunctionsMode.

Strict Mode Compatibility

Important

VM obfuscation needs to know at compile time whether code runs in strict mode. If your code relies on strict mode behavior, you must explicitly declare it.

Identifier Preprocessing

Recommended

The vmPreprocessIdentifiers option (enabled by default) renames all non-global identifiers to unique hexadecimal names before VM obfuscation. This step eliminates variable shadowing that can cause scope resolution issues in the VM bytecode.

Debug Protection

Pro

The vmDebugProtection option adds anti-debugging measures to the VM runtime, making it significantly harder to reverse-engineer your protected code.

More anti-debugging techniques will be added in future releases.

VM Options Reference

Using the NPM Package

Pro

You can use VM obfuscation in your build pipeline via the javascript-obfuscator npm package. The obfuscatePro() method connects to the obfuscator.io cloud service for VM-based bytecode obfuscation.

Installation

npm install --save-dev javascript-obfuscator

Usage

const JavaScriptObfuscator = require('javascript-obfuscator');

const sourceCode = `
function calculatePrice(qty, price) {
    const discount = 0.15;
    return qty * price * (1 - discount);
}
`;

const result = await JavaScriptObfuscator.obfuscatePro(
    sourceCode,
    {
        vmObfuscation: true,
        vmObfuscationThreshold: 1,
        compact: true
    },
    {
        apiToken: process.env.OBFUSCATOR_API_TOKEN
    }
);

console.log(result.getObfuscatedCode());

How VM Transforms Code

With vmTargetFunctionsMode: 'root' (default), VM obfuscation transforms the body of each root-level function into bytecode (depending on vmObfuscationThreshold), but keeps the function name unchanged.

// Input
function fibonacci(n) {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
}

// Output - function NAME is preserved, BODY is VM-transformed
function fibonacci(b) {  // name kept as-is
    return vm.call(...); // body converted to bytecode
}

This design maintains compatibility with code that calls these functions from the global scope or expects them on the global object. The function body is fully protected, but the name remains visible.

Hiding sensitive function names:

If a function name reveals what the code does (e.g., validateLicense, decryptData), use one of these approaches:

  • Option 1: Wrap in an IIFE (Recommended)

    Place sensitive functions inside an IIFE or any other function body. Functions inside other functions are not root-level, so they get fully VM-transformed including their names.

    // Wrap sensitive code in IIFE
    (function() {
        function fibonacci(n) {
            if (n <= 1) return n;
            return fibonacci(n - 1) + fibonacci(n - 2);
        }
        // Use fibonacci here...
    })();
    // "fibonacci" name is completely hidden in output
  • Option 2: Rename globals + encoding (Use with caution)

    Enable renameGlobals: true, vmPreprocessIdentifiers: true, vmBytecodeEncoding: true, and vmBytecodeArrayEncoding: true. This renames root-level identifiers and encrypts them in the bytecode.

Protection Against LLM Analysis

Modern LLMs (Large Language Models) like ChatGPT and Gemini in Thinking modes are capable of analyzing code patterns. On small input code, LLMs may attempt to predict what code does based on certain factors.

Factors that enable LLM analysis (VM Low preset):

  • Visible root-level names: Root-level function and variable names are preserved by default to maintain compatibility with code that relies on calling these from the global scope.

  • Unencrypted constant pool: Without bytecode encoding, the constant pool containing function names is stored in plain text.

  • Predictable VM structure: Without opcode/bytecode instructions shuffle, encryption, and other hardening options, LLMs can attempt to traverse small VM code and make assumptions.

How to prevent LLM analysis:

  • Hide global-level names: Wrap sensitive code in an IIFE or use renameGlobals. See How VM Transforms Code for details.

  • Enable bytecode encryption: Use vmBytecodeEncoding: true and vmBytecodeArrayEncoding: true with vmBytecodeArrayEncodingKey and vmBytecodeArrayEncodingKeyGetter to encrypt the constant pool and bytecode array.

  • Enable hardening options: Use vmInstructionShuffle,vmOpcodeShuffle, vmDecoyOpcodes, vmDeadCodeInjection, and other options available in VM Medium preset and above.

Troubleshooting VM Obfuscation Issues

VM obfuscation completely transforms your code into custom bytecode. Ideally, this transformation should handle all possible code patterns and edge cases seamlessly. However, due to the complexity of VM obfuscation, there are still edge cases that may not be fully supported. This means that VM-obfuscated code must be carefully tested in at least all happy-path scenarios before deployment.

If your code doesn't work after VM obfuscation:

  • 1. Ensure identifier preprocessing is enabled

    Check that vmPreprocessIdentifiers is enabled (default: true). This option eliminates variable shadowing issues that can cause scope resolution errors in VM bytecode. If it's disabled, try enabling it first.

  • 2. Narrow down the problematic code

    Use vmTargetFunctionsMode: 'comment' to selectively VM-obfuscate specific functions. Add the /* javascript-obfuscator:vm */ comment only to individual functions and test incrementally to identify which function causes the issue.

  • 3. Contact support with details

    Email support@obfuscator.io with as much information as possible:

    • Error message and stack trace
    • Environment (browser/Node.js version)
    • Obfuscator options/preset used
    • Obfuscator version (shown in the bottom-right corner of the editor)
    • Minimal code sample that reproduces the issue (ideally the narrowed-down problematic function)
VM Obfuscation | Obfuscator.io Documentation