unsafe-inline, unsafe-eval, and friends
What the unsafe-inline, unsafe-eval, unsafe-hashes, and wasm-unsafe-eval keywords allow in script-src, and when each is justified.
The unsafe- keywords each relax script-src in a specific way. They exist for
compatibility with code you cannot immediately change. Treat every one as a
temporary allowance to remove, not a default.
'unsafe-inline'
Allows all inline scripts, inline event handler attributes, and
javascript: URLs:
script-src 'unsafe-inline'
This effectively disables the XSS protection script-src provides, because an
injected inline script is now indistinguishable from a legitimate one. Prefer a
nonce or a hash instead. As noted on those
pages, a nonce or hash in the same directive causes browsers to ignore
'unsafe-inline', so you can list it purely as an old-browser fallback.
'unsafe-eval'
Allows string-to-code APIs:
script-src 'unsafe-eval'
This covers eval(), new Function(), and setTimeout / setInterval when
called with a string argument. Some older template engines and libraries need
it. Modern equivalents usually do not. Removing 'unsafe-eval' is often just a
matter of upgrading a dependency or passing a function instead of a string to
setTimeout.
'wasm-unsafe-eval'
Allows compiling and instantiating WebAssembly without allowing JavaScript
eval:
script-src 'wasm-unsafe-eval'
Before this keyword existed, running WebAssembly required the much broader
'unsafe-eval'. If you only need Wasm, use 'wasm-unsafe-eval' so JavaScript
eval stays blocked.
'unsafe-hashes'
Allows specific inline event handlers whose code matches a listed hash:
script-src 'unsafe-hashes' 'sha256-hashOfHandlerCode'
A normal script hash does not cover attribute handlers like
onclick="doThing()", because the hash is computed over script element content,
not attributes. 'unsafe-hashes' extends hashing to those handlers. It is
weaker than moving the handler into a hashed or nonced <script> block, so use
it only when you cannot edit the markup.
Removing them
A practical order to tighten a policy:
- Replace
'unsafe-inline'with nonces or hashes. - Swap
'unsafe-eval'for'wasm-unsafe-eval'if only Wasm needs it, then remove it entirely once dependencies allow. - Move inline
onclickhandlers into scripts and drop'unsafe-hashes'.
Watch your violation reports while doing this, so you catch anything that breaks before users do.