Guide · Magento 2.4.7+

Magento 2.4.7 Content Security Policy explained

Magento 2.4.7 made Content Security Policy real on checkout. This is how storefront vs Admin, report-only vs restrict, and hosts vs hashes vs nonces actually behave, and why adding a domain to csp_whitelist.xml often does not stop the console errors.

  1. What 2.4.7 changed
  2. Storefront vs Admin
  3. Report-only vs restrict
  4. How to read the console
  5. Hosts, hashes, nonces, and SecureHtmlRenderer
  6. Why a whitelist host is not enough
  7. Do not disable Magento_Csp
  8. What to do next

What 2.4.7 changed

Before 2.4.7, many stores ran Magento’s CSP module in report-only mode, or treated the header as noise. In Magento Open Source and Adobe Commerce 2.4.7 and later, payment pages default to restrict mode. The Content-Security-Policy header on those pages does not include 'unsafe-inline' inside script-src. Only scripts Magento has a reason to trust — a whitelisted host, a hash, a nonce, or a tag rendered through Magento’s secure HTML helper — are allowed to run.

Other storefront pages stay in report-only by default. The browser still logs violations, but it does not block them. That is why a tag can “work everywhere except checkout,” and why an upgrade to 2.4.7 looks like a payment bug when it is actually CSP.

Adobe documents this in the Content Security Policies PHP guide and in the knowledge base article Troubleshoot storefront checkout page in CSP restricted mode.

Storefront vs Admin

Magento keeps two policies. The storefront policy is what customers hit on the catalog, CMS pages, and checkout. The Admin policy is what Magento sends on the Admin panel, including Admin payment screens. They are configured separately. A host you allow for the storefront is not automatically allowed in Admin, and the reverse is also true.

When a merchant says “CSP is blocking us,” ask which area. A Google Tag Manager error on the homepage is storefront. A payment iframe failing on checkout is storefront checkout, which is the restrict-mode page. A Magento Admin payment integration failing is Admin CSP, which this guide does not treat as the same problem.

Report-only vs restrict

Magento’s CSP module can send either:

On 2.4.7+, Magento sets restrict mode for the checkout action storefront_checkout_index_index (and the matching Admin payment pages). Everything else on the storefront is report-only unless you change Magento’s CSP config. The default lives in Magento/Csp/etc/config.xml. Custom modules can override mode and inline-script policy per action; that is how some stores quietly put checkout back into report-only after an upgrade, which stops the errors and also stops the protection.

Look at the response header on the page that fails, not on a random CMS page. Report-only on the homepage and restrict on /checkout is normal.

How to read the console

In Chrome or Firefox DevTools, open Console and reload the failing page. Magento CSP errors look like:

Refused to load the script 'https://example.com/widget.js' because it violates
the following Content Security Policy directive: "script-src 'self' ..."
Refused to execute inline script because it violates the following
Content Security Policy directive: "script-src ..." Either the 'unsafe-inline'
keyword, a hash ('sha256-…'), or a nonce ('nonce-…') is required to enable inline execution.

The first line names the directive (script-src, connect-src, frame-src, style-src, img-src, and so on) and either a URL or “inline script.” A third-party script, pixel, or API almost always needs a host on the matching directive. An inline <script> in a template, CMS block, or payment module needs a hash or nonce, not a host. One checkout flow often needs both.

Confirm the live header under DevTools → Network → the document request → Content-Security-Policy (or Content-Security-Policy-Report-Only). If the host or hash is not in that header, Magento is not sending it for that store view, no matter what is in XML.

Hosts, hashes, nonces, and SecureHtmlRenderer

Magento’s whitelist file, etc/csp_whitelist.xml in a module, can add three kinds of value to a directive:

hostA domain such as js.stripe.com or *.example.com. Lets Magento load a resource from that origin.
hashA SHA-256 digest of a specific inline script or style, Base64-encoded. Magento adds it to the header so that exact inline block may run.
schemeA URL scheme such as https or data. Rarely what you want for a payment or analytics fix.

For inline scripts Magento itself owns, Adobe’s supported paths are:

Putting 'unsafe-inline' back on checkout via config.xml will silence the errors. It also undoes the 2.4.7 payment-page hardening. Treat that as a temporary diagnostic, not a fix.

Why a whitelist host is not enough

This is the usual 2.4.7 trap. A developer adds the payment or tag domain to script-src in csp_whitelist.xml, deploys, flushes cache, and checkout still shows Refused to execute inline script. The host entry did its job: the external file is allowed. The inline bootstrapping Magento, a payment module, or a custom theme still injects on the page is a different kind of source. Restrict mode on checkout refuses it until it is hashed, nonced, or rendered through SecureHtmlRenderer.

The other usual miss is the wrong directive. Whitelisting script-src does not allow connect-src XHR/fetch calls or frame-src iframes. Stripe, Google Tag Manager, and most payment and analytics tools need more than one directive. See the Stripe CSP and Google Tag Manager CSP notes for those two. If the XML is in place and the host still never appears in the header, use the csp_whitelist.xml troubleshooting checklist (module enabled, cache, store scope, restrict vs report-only header name).

Do not disable Magento_Csp

Guides that tell you to disable Magento_Csp or force report-only on checkout are skipping the upgrade work. The module is a dependency for other Magento code. Disabling it can fail setup:upgrade or leave payment pages unprotected. If checkout is broken after 2.4.7, the job is to identify each blocked host and each inline script, then allow those sources properly.

What to do next

Work from the console, not from a copied whitelist you found on GitHub.

  1. Reproduce on the page that fails, usually /checkout, and note whether the header is enforce or report-only.
  2. For each Refused to load / Refused to connect URL, add that host to the directive named in the error, in a module’s csp_whitelist.xml or in Admin if you use a whitelist module.
  3. For each Refused to execute inline script, find the template or module that printed it. Prefer SecureHtmlRenderer or a nonce. Use a hash only when the inline bytes are stable.
  4. Flush Magento cache (and full page cache if you use it). Confirm the new host or hash is in the response header, then reload.

Adding a third-party host is configuration. Fixing inline checkout scripts in custom or third-party modules is Magento development: that is consulting if you do not want to own the patch.

If the remaining work is “marketing keeps adding pixels and we do not want a deploy each time,” CSP Manager for Magento puts storefront host, hash, and scheme rules in Magento Admin. It does not replace hashes and nonces for inline checkout code, and it does not change Admin CSP. The usage guide shows the Admin screens.