Security engineering
It’s a fair worry, and a good one to ask before you ship: if you run a strict Content Security Policy — no unsafe-eval, no unsafe-inline — will obfuscating your JavaScript force you to punch a hole in it? For one whole class of tools, yes. For modern obfuscation of the kind we do, no. The distinction is worth understanding, because “we had to allow unsafe-eval for the obfuscator” is a real regression teams sometimes accept without realizing they didn’t have to.
The thing CSP actually blocks
A strict CSP’s two most valuable restrictions are unsafe-eval (no eval(), no new Function(), no string-to-code execution) and unsafe-inline (no inline <script> without a nonce or hash). They exist because string-to-code execution is the classic injection primitive — if an attacker can get a string into eval, they run code. Turning those off is one of the highest-leverage things a security team can do, so anything that forces them back on is a genuine cost.
Why old “packers” break under it — and modern obfuscation doesn’t
The confusion comes from an older generation of tools. Classic JavaScript packers (the eval(function(p,a,c,k,e,d){...}) style) work by shipping the real code as a string and calling eval() to unpack it at runtime. That is fundamentally incompatible with a strict CSP: no unsafe-eval, no unpack, broken page. If your mental model of “obfuscation” is that pattern, the worry is justified.
Modern obfuscation doesn’t work that way. Its transforms are ordinary JavaScript operations, not string-to-code execution:
- String encryption / string arrays decode via array indexing and normal string functions — no
eval.
- Control-flow flattening is a
switch-driven state machine — regular control flow, no eval.
- VM bytecode runs marked functions on an inlined interpreter — a normal function that switches over opcodes. An interpreter is code that reads data, not code that executes strings; it needs no
eval.
Our engine emits none of eval, new Function, or other string-to-code calls as part of these transforms, so the protected output runs under a strict CSP without unsafe-eval. (As always, test your specific build against your specific policy before you ship — but the technique itself doesn’t require the weakening.) If a tool tells you to add unsafe-eval to accommodate its output, that’s a property of that tool, not of obfuscation in general.
The CSP question that is about you, not the obfuscator
There is one CSP interaction that has nothing to do with the transforms and everything to do with how you include the script: inline vs. external. If you paste an obfuscated bundle straight into an inline <script>...</script>, you’ll need unsafe-inline or a per-response nonce/hash — but that’s true of any inline script, obfuscated or not. The clean answer is the same as for unprotected code: serve it as an external .js file from your own origin, which a strict CSP allows via script-src 'self'. Obfuscation doesn’t change that calculus.
Two smaller notes while you’re here: don’t obfuscate the CSP nonce-wiring or config itself, and don’t let “we’re adding obfuscation” become the reason a strict policy quietly gets relaxed. If anything, obfuscation and a strict CSP are complementary — one raises the cost of reading your code, the other shrinks the runtime attack surface.
The short version
Eval-based packers break strict CSP; modern obfuscation doesn’t, because its transforms are ordinary code, not string-to-code execution. Keep unsafe-eval off, serve your protected code as an external file so you can keep unsafe-inline off too, and verify the result against your own policy. You should not have to weaken your CSP to protect your JavaScript.
Related reading:
Does obfuscation slow down your app? ·
Does obfuscating JavaScript hurt your SEO? ·
Your source maps are publishing your source code.