ddtcorex

09 Sept 2026 · 3 min read

Content Security Policy and subresource integrity in Magento 2

How to roll out a Content Security Policy in Magento 2 without breaking the storefront, wire subresource integrity for third-party scripts, and the mistakes that make CSP cosmetic.

Part 2 of the Magento 2 security series — implementation-focused. The overview is at /blog/magento2-security.

Why CSP matters here

A storefront loads JavaScript from many sources: the theme, payment iframes, analytics, tag managers, and assorted third-party widgets. A Content Security Policy (CSP) tells the browser which sources are allowed to execute script, load styles, or embed frames. Without it, a single injected <script> — via a stored XSS, a compromised dependency, or a malicious admin widget — runs with full page privileges.

Magento ships native CSP support (a csp_whitelist.xml and a report-only mode), so you do not need an extension to start. You need discipline to do it without breaking checkout.

Start in report-only mode

Never flip CSP to enforce on day one. Magento's CSP module supports a report-only mode that logs violations to the browser console and (optionally) a collector, without blocking anything. Run it for one or two release cycles:

<!-- etc/csp_whitelist.xml -->
<?xml version="1.0"?>
<csp_whitelist xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Csp:etc/csp_whitelist.xsd">
    <policies>
        <policy id="script-src">
            <values>
                <value id="self" type="host">self</value>
            </values>
        </policy>
    </policies>
</csp_whitelist>

While in report-only, watch the console on every key route — home, category, product, cart, checkout, and the admin. Each violation is a source you must decide to allow or fix at the source.

Whitelisting the right way

Add only the hosts the storefront actually uses, and be as specific as possible:

<policy id="script-src">
    <values>
        <value id="payments" type="host">https://js.payments-provider.example</value>
        <value id="analytics" type="host">https://www.googletagmanager.com</value>
    </values>
</policy>

Avoid unsafe-inline and unsafe-eval — they defeat most of CSP's value. If a vendor script demands them, that is a signal to find a better integration or to hash/nonce the specific inline block (Magento can emit nonces for inline scripts via its CSP module).

Subresource integrity for third-party scripts

For scripts loaded from outside your control (CDNs, vendor JS), add an SRI hash so a tampered file fails to load rather than executing:

<script src="https://cdn.vendor.example/widget.js"
        integrity="sha384-<base64-hash>"
        crossorigin="anonymous"></script>

Magento's layout does not emit SRI automatically for arbitrary CDN scripts, so when you add a vendor <script> through a layout block/referenceBlock, compute the hash from the exact file you ship and pin it. If the vendor updates the file without telling you, the hash mismatch blocks it — which is the point: no silent supply-chain execution.

Mistakes that make CSP cosmetic

  • Leaving unsafe-inline because "it was easier." This allows any inline script, including injected ones. Solve the specific inline need with a nonce instead.
  • Whitelisting * hosts. A script-src https://* style rule is barely better than none. Pin hosts.
  • Forgetting the admin. The admin panel loads its own scripts and widgets; a CSP that only covers the storefront leaves the highest-privilege surface unprotected. Test admin routes too.
  • Skipping checkout after a theme change. A new payment method or a Hyva checkout upgrade changes the script sources; re-run report-only after any such change (see the Hyva performance post for the checkout-CSP interaction).

Verification

  • Report-only ran for a full release cycle with zero unexpected violations on key routes.
  • unsafe-inline / unsafe-eval absent from the enforced policy.
  • Third-party scripts carry SRI hashes.
  • Admin routes covered.
  • A violate-and-confirm test: inject a <script> from an unknown host and confirm the browser blocks it.

What's next

CSP protects the browser surface; the next post hardens the admin itself — 2FA, access control, and the mistakes that leave a superuser exposed.

Next in this series: Two-factor auth and admin access hardening — /blog/magento2-security-2fa

magento2securitycspfrontend