The PCI DSS 4.0.1 enforcement deadline passed on 31 March 2025. Fourteen months later, the first wave of QSA audit reports against the new requirements is hitting WooCommerce stores — and three findings keep coming back. None of them are exotic. All of them are fixable in an afternoon. Most stores still haven’t.
Who this is for: WooCommerce stores using a hosted payment iframe (Stripe Elements, Braintree Hosted Fields, Authorize.net Accept.js, Adyen Drop-in). If you ever see a raw PAN on your server, this post is the wrong starting point — you need a QSA, not a blog.
What 4.0.1 actually requires
Most WooCommerce stores qualify for SAQ A — the shortest self-assessment, because the card data never touches their servers. 4.0.1 expanded SAQ A in two ways that catch people off guard:
- Requirement 6.4.3 — you must inventory and authorise every script that loads on a payment page, and detect unauthorised changes.
- Requirement 11.6.1 — you must monitor the integrity of the HTTP headers and payment-page content delivered to the browser, and alert on tampering.
Both exist because of Magecart — the family of attacks where an injected script reads card details out of an iframe’s parent page before they reach the gateway. The new requirements don’t ask you to prevent the attack; they ask you to detect it.
Finding 1 — No script inventory
The auditor asks for the list of every JavaScript loaded on /checkout. The store owner forwards the question to the developer. The developer runs view-source, counts 47 scripts (Google Tag Manager alone pulls in 18), and realises nobody has ever vetted them.
The fix: generate the inventory programmatically and store it under version control.
// Capture every script tag rendered on checkout
add_action('wp_print_scripts', function() {
if (!is_checkout()) return;
global $wp_scripts;
$log = [];
foreach ($wp_scripts->queue as $handle) {
$src = $wp_scripts->registered[$handle]->src ?? '';
$log[] = compact('handle', 'src');
}
file_put_contents(
WP_CONTENT_DIR . '/pci/checkout-scripts-' . date('Y-m-d') . '.json',
wp_json_encode($log, JSON_PRETTY_PRINT)
);
}, 999);
Diff the file weekly. Anything new gets an authorisation review or it gets removed. The auditor wants to see a process, not a perfect score.
Finding 2 — No script-integrity monitoring
You’ve inventoried the scripts. You haven’t verified that the file at https://cdn.example.com/analytics.js hasn’t been modified by an attacker. Sub-Resource Integrity (SRI) hashes solve this — for static URLs. They’re useless for tag managers that load code dynamically.
The fix: Content Security Policy in report-only mode pointed at a real endpoint.
// In your checkout response headers:
Content-Security-Policy-Report-Only:
script-src 'self' https://js.stripe.com https://www.googletagmanager.com;
report-uri https://your-store.com/wp-json/softxone/v1/csp-report;
report-to csp-endpoint;
Build the REST endpoint to log violations to a separate table and alert on volume spikes. The point isn’t to block — blocking on checkout breaks revenue. The point is to know, within minutes, that an unauthorised script appeared.
Finding 3 — Admin and customer accounts share session storage
This one isn’t strictly a 4.0.1 addition — it’s 8.4.2, MFA on all non-console administrative access — but it’s the requirement most WooCommerce stores fail. The store owner logs into /wp-admin/ with a password. There’s no second factor. The auditor flags it. The store installs a free MFA plugin. The plugin authenticates against the same wp_users table customers use. Suddenly every customer login also demands a TOTP code and conversion craters.
The fix: a plugin that scopes MFA enforcement to capability, not to user table. Anyone with edit_posts or above gets MFA; customer role is exempt. Two-Factor and Wordfence both support this, but you have to configure it — the defaults are everyone-or-nobody.
⚠ Don’t confuse SAQ A with “not in scope”. The new SAQ A is roughly twice the length of the old one. If your acquirer hasn’t asked for your 2026 attestation yet, they will — and the form they send is no longer the two-page checkbox sheet from 2023.
What this looks like in production
On the stores we operate, full 4.0.1 alignment takes roughly:
- Half a day to audit and prune the script inventory on the checkout page.
- One day to wire up CSP report-only, the reporting endpoint, and alerting.
- Half a day to scope MFA correctly and roll it out to admins.
- One day to write the documentation the QSA actually wants — the policy, the change log, the alert run-book.
Three days of work. The penalty for not doing it is rarely a fine — it’s the acquirer raising your card-processing fees, or quietly moving you to a higher-risk MCC, the next time your SAQ comes up. By the time you notice on the statement, you’ve been paying for months.
What we’d do this week
- Open your checkout in an incognito browser. Open DevTools → Network → JS. Count the requests. If it’s over 20, you have a script-inventory problem before you start.
- Pull your most recent SAQ. If it says “version 4.0” anywhere, it’s already out of date — 4.0.1 superseded it.
- Ask whoever set up GTM what’s in the container. If they left, treat the container as untrusted until reviewed.
- Confirm MFA is enforced for every account with
edit_postsor above — and only those accounts.
PCI compliance is not security. But the 4.0.1 changes happen to overlap almost exactly with the controls that would have prevented the Magecart wave of 2023–2024. Treat it as the forcing function, not the goal.