VM Obfuscation with eval and new Function
How VM obfuscation handles dynamic code construction (direct eval and the Function constructor), what gets bytecoded versus skipped, the warnings the obfuscator emits, and how to diagnose ReferenceError at runtime.
Why this matters
Indirect eval and the Function constructor execute in global scope. They cannot read the caller’s local variables, but can still fail if they reference globals that were renamed or removed. A static body using only its own parameters, such as new Function("a", "b", "return a + b"), avoids that dependency. Review warnings and test the final bundle; changing eval syntax alone does not make arbitrary dynamic code safe.
The compiler also conservatively detects eval?.(code). JavaScript defines this optional-call form as indirect eval; compiler detection does not change that language behavior. vmForceCompileDynamicCode overrides skipping, but cannot repair scope or renamed-identifier dependencies.
Detecting the problem before runtime
The obfuscator emits non-fatal warnings via the API so you can catch these patterns in CI before shipping. Two warning types are relevant:
DynamicCodeRenameRisk- a function contains a dynamiceval/new Function/Functioncall whose body is built at runtime.VMDynamicCodeSkipped- VM bytecoding was skipped for a function because of one of the above patterns. Includes the function name (if available) and the kind of construct that triggered the skip.
If a warning type is expected in your build and you would rather silence it at the source than filter it in CI, the
warnings option (v7.8.0+) controls what getWarnings() emits: 'none' suppresses everything, and a per-type map
like { VMDynamicCodeSkipped: false } mutes just one type while keeping the rest.
Workarounds
Set vmTargetFunctionsMode to comment, then mark each selected function with /* javascript-obfuscator:vm */. Preserve these comments until the obfuscation step.
