Every Magento 2 install ships a Content-Security-Policy-Report-Only header that is turned on by default. The field those reports are meant to be delivered to ships empty. Four Admin fields, no code, and you get the script inventory PCI DSS 6.4.3 asks for.
Magento 2 has shipped the Magento_Csp module since 2.3.5, and it is enabled out of the box. The storefront and the Admin both send a report-only policy, which means every browser that loads a page builds a violation report for anything outside that policy — and then finds no endpoint to send it to.
The reporting endpoint is a separate setting, and its default is empty. Nobody turned this off. It arrived that way, and on most stores it has stayed that way through every upgrade since.
Content-Security-Policy-Report-Only: default-src 'self' https: ...
script-src 'self' 'unsafe-inline' 'unsafe-eval' https: ...
(no report-uri directive, no report-to directive)
The control is deployed. The evidence is being thrown away.
We crawl the top million sites and record what security headers they actually send. In the August 2026 crawl, 2,568 of those sites were taking card payments behind a report-only CSP with no reporting endpoint anywhere in the policy.
87% of every payment-taking site we found with this exact misconfiguration runs on one platform. That is not 2,236 independent decisions — it is a platform default reaching its logical conclusion.
Store Leads counts over 100,000 live Magento stores. The crawl only sees the ones big enough to rank, so the population carrying this default is far larger than the sample we can measure directly.
If you want to check your own store before reading any further: load your storefront, open developer tools, and look at the response headers for Content-Security-Policy-Report-Only. If it has no report-uri in it, this page is about you.
This catches people out on upgrade, so it is worth being precise about. Two pages enforce their policy; everything else reports only.
| Page | Default mode | Set by |
|---|---|---|
| Storefront — everything else | Report-only | Magento_Csp |
| Admin — everything else | Report-only | Magento_Csp |
| Storefront — One Page Checkout | Restrict | Magento_Checkout |
| Admin — Create Order | Restrict | Magento_Sales |
Those two enforcing pages also drop 'unsafe-inline' from script-src. An inline script that was merely noisy before the upgrade stops running afterwards — and with no reporting endpoint set, nothing tells you it happened.
Go to Stores > Configuration > Security > Content Security Policy > Mode. Each of the four groups has a single Report URI field. They are URL-validated, so paste the full endpoint including the scheme.
Because checkout enforces while the rest of the storefront only reports, a single endpoint across all four mixes enforced violations and report-only violations into one data set. Set them separately and the two stay readable:
| Admin field | Endpoint to paste |
|---|---|
| Storefront Default | https://abc123.report-uri.com/r/d/csp/reportOnly |
| Storefront > One Page Checkout | https://abc123.report-uri.com/r/d/csp/enforce |
| Admin Default | https://abc123.report-uri.com/r/d/csp/reportOnly |
| Admin > Create Order | https://abc123.report-uri.com/r/d/csp/enforce |
abc123 is your own subdomain, which you will find on the Setup page in your account. A page-specific field left empty falls back to the default for its area, so the two defaults alone are enough to start collecting.
Filling in a reporting endpoint does not change what your policy permits. A store on the report-only default blocks nothing before you do this and blocks nothing after. What changes is that you can see what it would have caught.
Requirements 6.4.3 and 11.6.1 apply to the page that takes the card. Magento already enforces a policy there. What it does not do is keep any record of what that policy saw.
Every script on the payment page must be known, approved and documented. Reports from real browsers give you an inventory of what actually executed — including scripts a third-party extension injected that nobody documented.
Changes to payment page scripts and to the security headers themselves must be detected and acted on. Continuously, not at your next assessment.
Magento gives you the control. The reporting endpoint is what turns it into evidence an assessor can read.
Card skimming groups target Magento specifically, and they have done for years. The attack does not need a vulnerability in your code — an unpatched extension, a compromised third-party script, or an admin session is enough to get a few lines of JavaScript onto the checkout page. From there the skimmer reads the card fields directly out of the DOM as the customer types.
A CSP report is one of the earliest reliable signals that this has happened: a script appearing on a page it has never run on before, or data heading for a destination that was never authorised. That signal is being generated on your store today and discarded before anyone sees it.
New script, modified script, unauthorised dependency — flagged against an inventory built from real page loads rather than from asking around.
Learn more about Script Watch →csp_whitelist.xml. You should know when they do.Third-party Magento extensions ship their own csp_whitelist.xml entries, which widen your policy on install without asking. Policy Watch monitors the deployed header and tells you the moment it changes.
Detects when data starts leaving your checkout for somewhere it should not. Destinations, anomalies, and a behavioural record — which is what a skimmer looks like before anyone reports a fraudulent charge.
Learn more about Data Watch →Create an account, copy your endpoint from the Setup page, and paste it into the four Admin fields. Flush the cache and the reports your store has been discarding start arriving instead. Nothing of ours runs on your storefront and there is no extension to install.
Four fields. No code. Live in under an hour.
Running this across a portfolio of client stores? Talk to our team →
Magento_Csp module, and it is on. The storefront and the Admin both send Content-Security-Policy-Report-Only, so every visitor's browser is already generating violation reports. What ships empty is the field those reports are supposed to be sent to, which means the browser builds each report and then has nowhere to deliver it.
'unsafe-inline' from script-src. Because the modes differ, point the two enforcing pages at your enforce endpoint and the two defaults at reportOnly, or enforced and report-only violations arrive mixed into one data set.
Magento_Csp module and configure it identically, so everything here applies to Adobe Commerce, Magento Open Source and Mage-OS alike.
csp/mode/{area}/report_uri in a custom module's etc/config.xml, with per-page overrides using Magento's full action name. Our Adobe Commerce and Magento guide has the XML.
It takes four fields to stop throwing it away.