Fix guide · high · csp_unsafe_eval

CSP allows 'unsafe-eval' in script-src

What this rule means

Your Content-Security-Policy header includes 'unsafe-eval' in script-src. JavaScript's string-as-code APIs (eval(), Function(), setTimeout('code', n), setInterval('code', n)) are permitted. Often left over from a build tool that needed it during development.

Why it matters

'unsafe-eval' doesn't directly bypass CSP — an attacker still needs to get script execution somehow first. But once they have any code-execution primitive, eval() and Function() let them assemble payloads from string concatenation that pattern-matching defences can't see. The compounding effect: many XSS-mitigation libraries assume CSP blocks eval, so their defence-in-depth weakens when eval is permitted.

The most common reason 'unsafe-eval' ends up in production CSP: a development tool (webpack's eval-source-map devtool, some templating engines, older Vue versions, some animation libraries) needed it locally, and the CSP that worked in dev got copied to production wholesale.

How to fix it

  1. Identify what needs eval. Search your codebase: grep -rE "\beval\(|new Function\(" src/. Inspect each match. Most are removable (string templating that should use real templates; legacy code that should use JSON.parse).
  1. Switch dev tooling. webpack's devtool: 'eval-source-map' is the most common offender. Switch to source-map or cheap-source-map. Vue: ensure you're using the runtime-only build, not the runtime+compiler build (the compiler uses new Function).
  1. Drop 'unsafe-eval' from production CSP. Validate the build still works.

If you have a third-party library that genuinely needs eval and there's no alternative: isolate it in an iframe with its own scope, OR scope the eval permission to that library's source via a separate script-src-elem / script-src-attr discipline.

Full guide: /blog/csp-bypass-vibe-coded.

Did vibecheck flag this on your app?

If you reached this page from a vibecheck inspection report, the redacted match in your scan output is the exact string we found in your bundle. After applying the fix above, run the inspection again — the finding should clear.

Run another inspection