Because a CSP that sets default-src or script-src blocks eval() and similar APIs unless you allow them. Some older widgets build code from strings. The quick fix, unsafe-eval, weakens the policy. Better options are updating the widget, replacing it, or using Trusted Types to narrow the risk.
What the browser does
MDN's CSP guide explains that if a policy contains a default-src or script-src directive, eval() and similar APIs are not allowed to execute. The same applies to inline scripts without a nonce or hash. This is deliberate. These APIs turn text into running code, which is exactly what an injection attack wants.
When a widget calls eval, the browser refuses and logs a violation. The visible symptom is a button that does nothing, a payment field that never loads, or a script error on checkout right after a policy change.
How to confirm the cause
- Open the browser console on the failing page. Look for a message about blocked script evaluation.
- If you ran the policy in report-only mode first, check the reports for the page. The effectiveDirective field will name the script rule involved.
- Find which script made the call. Reports include source file and line information where the browser can provide it.
- Check whether the code is yours, a vendor's file or a library bundled inside either.
Options, from best to worst
| Option | What it means | Trade-off |
|---|---|---|
| Update the widget | Newer versions often avoid eval | Needs vendor support or a version bump |
| Replace the widget | Pick one that works under a strict policy | Migration work |
| Fix your own code | Replace eval with safer constructs | Developer time |
| Trusted Types | Define a policy so only approved input reaches the call | Needs setup and testing |
| unsafe-eval | Allow eval everywhere in the policy | Weakens the protection for the page |
MDN says developers should avoid unsafe-eval for the same reasons as unsafe-inline. It also notes that sometimes it is hard to remove usages of eval and similar methods, and in those situations Trusted Types can make them safer by ensuring the input meets a defined policy. The trusted-types-eval keyword exists for this case. Unlike unsafe-inline, it only overrides the block in browsers where Trusted Types are supported and enabled, so the methods stay blocked elsewhere.
Do not widen the policy sitewide for one widget
A common shortcut is to add unsafe-eval to the whole policy to keep one widget alive. On a checkout page that trades away protection for the sake of one script. Where possible, scope the exception: apply a looser policy only to pages that truly need it, and keep checkout strict.
Decide whether the widget belongs on checkout at all
Ask what the widget does. If it is a chat bubble or a popup, it probably does not need to be on the payment step, and removing it is the cleanest answer. Our post on which pages should not run marketing tags can help.
Document what you chose
Whichever option you pick, record it in the tag register with the date and the reason. An exception without an owner and a review date tends to become permanent.
Where Safeguard fits
Safeguard's SBOM and dependency scanning can show whether a library that relies on dynamic code evaluation is in your build, and policies can enforce what you allow. The CSP itself is configured in your server or CDN. A free scan is at gold.safeguard.sh/scan.
Quick check
Is unsafe-eval ever acceptable?
It is a trade-off. MDN advises avoiding it. If you must, limit it to pages that need it and set a date to remove it.
Will report-only mode show eval problems?
Yes. It reports violations without blocking, so you can fix them before enforcement.
Sources
Last reviewed: 19 October 2026.