Documentation

Deep Obfuscation

Reference guides for release workflows, command-line usage, cross-file protections, and the desktop app.

Inside the Docs

Practical guides for real release work.

How-to guides Start with release sequencing and command-line usage, then move into feature-specific references.
Advanced protection Browse cross-file controls like Replace Globals and Protect Members when a build spans multiple scripts.

Deep Obfuscation

  • DeepObfuscate
  • Basic

Deep Obfuscation is an advanced form of Name Mangling that pushes identifier reuse further. Rather than giving every identifier in the file a distinct short name, it reuses the same names in different scopes wherever the language permits, so a name stops being a unique handle on a value.

What it does

Plain name mangling assigns each identifier its own generated name, which means the output is still a one-to-one relabelling of your source. Rename them back and you have your program. Deep Obfuscation removes that one-to-one property: after it runs, seeing a tells you nothing, because a in one scope and a two frames down are unrelated values.

Without Deep Obfuscation:

function a(b, c) {
    function(d, e) {
    }
}

With Deep Obfuscation enabled:

function a(a, b) {
    function(a, b) {
    }
}

Note the outer function is now called a and its own first parameter is also a — legal JavaScript, since the parameter shadows the function name inside the body.

Why the ambiguity matters

Shadowing attacks the technique that makes obfuscated code tractable: building a mental — or scripted — symbol table. A reader tracing a through a call chain has to re-derive which a they are looking at at every scope boundary, and a script that renames identifiers back to readable names has nothing consistent to rename, because the same token legitimately means different things in different places.

It also shrinks output. Reusing a small pool of names means shorter names overall, which is why the transform tends to pay for itself in bytes even before compression.

The honest boundary: this raises the cost of reading, and it does not change what the code does. Tooling that works on scopes rather than names — which includes any serious analysis, and increasingly includes LLM-assisted review — handles shadowing correctly, because a real scope analysis never confused the two as in the first place. Treat this as raising the floor against manual and scripted reading, and see AI resistance evidence for how we describe the limits of that claim.

Configuration

{
  "options": {
    "ReplaceNames": true,
    "DeepObfuscate": true
  }
}

If you are migrating from the open-source javascript-obfuscator package, its controlFlowFlattening option maps to DeepObfuscate together with FlatTransform — that single upstream flag covers two options here. See npm migration.

Test more carefully than usual

Deep Obfuscation is a scope-sensitive transform, which makes it more demanding on the engine's scope analysis than plain renaming. That analysis has to get several JavaScript details exactly right — var hoisting out of blocks, function declarations in loop bodies, class bodies as nested scopes, and the arguments object inside a function whose parameters have been renamed. Each of those is a place where an incorrect rename produces code that parses cleanly and behaves differently.

  • Run your full test suite against protected output, not a smoke test. A shadowing bug typically surfaces as a wrong value, not a crash.
  • Pay attention to closures. Code that captures a loop variable, or relies on a named function expression referring to itself, is the highest-risk shape.
  • Enable it on its own first. Turn on DeepObfuscate with name mangling and nothing else, confirm green, then layer structural transforms.
  • Use compatibility validation to catch the mechanical cases before you run anything.

Related options

  • Flat Transform rewrites control flow into state-machine dispatch — structure rather than names, and the natural partner to this option.
  • Code Transposition reorders statements so source order stops implying execution order.
  • Move Nested Function relocates nested functions away from their call sites.
  • Variable Exclusion List holds specific names out of every renaming transform, including this one.
Use it when: you already want Name Mangling, you need a stronger result, and you are prepared to test the output more carefully before release. If you cannot run a real test suite against protected output, stay on plain name mangling — an untested strong transform is a worse outcome than a tested weak one.

Frequently asked questions

What does this add over plain name mangling?

It removes the one-to-one relationship between original names and generated ones. Plain mangling is still a relabelling, so recovering readable names recovers your program's structure. With this option the same short token legitimately means different things in different scopes, so there is no consistent mapping to reverse and a reader has to re-derive which value they are looking at at every scope boundary.

Why does it usually make output smaller?

Because reusing a small pool of names means shorter names overall. Where plain mangling has to keep allocating distinct tokens as the identifier count grows, shadowing lets the same short token be reused in unrelated scopes. That tends to pay for itself in bytes before compression is applied, which makes it one of the few transforms that is not a straight size trade.

Does shadowing defeat automated analysis?

It defeats analysis that works on names, and not analysis that works on scopes. Any serious tool builds a scope tree rather than a symbol table keyed on text, and a correct scope analysis was never confused about which value a token referred to in the first place. The honest description is that this raises the floor against manual reading and against scripted rename-back tooling, which is a real and useful increase, rather than that it stops analysis.

What should we test more carefully with this option on?

Anything that reads a name at run time rather than resolving it at parse time, and anything that depends on how a function reports itself. Run your real test suite against protected output, exercise error paths so you see how stack traces look, and check any code that inspects function names or arguments. The general rule on this page is worth repeating: an untested strong transform is a worse outcome than a tested weak one.

How does it map from the open-source package's options?

The upstream control-flow flattening flag corresponds to this option together with the flat transform, so one setting there becomes two here. That is one of the cases where a migrated configuration needs a review rather than a direct copy, and the migration reference lists it alongside the other correspondences.

Does it require name mangling to be enabled?

Yes, it operates on the renaming pass rather than replacing it, so both settings go in the configuration together. If renaming is off there is nothing for the ambiguity to be applied to. Enable renaming first, get a protected build passing your tests, and then add this option as a second step so that if something breaks you know which change caused it.

Try this in the online obfuscator

Paste your own code and see this option applied, or compare plans for larger projects and the desktop app.

Try It Free See Pricing