PCI DSS SAQ A Scripts: How to Prove Eligibility

PCI DSS SAQ A Scripts: How to Prove Eligibility

SAQ A is no longer a short form. The part that catches merchants out is the PCI DSS SAQ A scripts question: a single line of eligibility wording that asks you to confirm your site is not susceptible to attacks from scripts that could affect the payment page. It reads like a formality. It is not. It is written as a confirmation rather than as a numbered control, which is exactly why thousands of merchants tick it every year without a single document behind the tick.

This piece treats that line as an evidence problem. What goes in the folder, who signs it, how to build each artefact with tools you already pay for, and the configuration drift that quietly voids the claim between one self-assessment and the next.

What SAQ A now asks about the scripts on your payment page

The Payment Card Industry Security Standards Council published PCI DSS v4.0 in March 2022 and v4.0.1 in June 2024. Two things changed for small e-commerce merchants. The eligibility criteria at the front of SAQ A gained the script sentence. And two requirements that had been future-dated, 6.4.3 and 11.6.1, became mandatory on 31 March 2025.

Requirement 6.4.3 asks you to manage the scripts loaded and executed on the payment page: authorise each one, confirm its integrity, and keep a written inventory with a business justification. Requirement 11.6.1 asks for a mechanism that detects and alerts on unauthorised change to the HTTP headers and the content of the payment page as received by the consumer browser. Both appear in the SAQ A question set for merchants who embed the payment form in their own page rather than sending the customer away to the provider. The detail of which questions apply to which model has moved more than once, so read the current SAQ A from the PCI SSC document library rather than a version your acquirer emailed you in 2023. The longer explanation of what those two requirements actually ask for sits in our breakdown of requirements 6.4.3 and 11.6.1.

SAQ A in v3.2.1 ran to a couple of dozen questions and could be completed in an afternoon by someone who had never seen the checkout code. The v4.0.1 version is a different document. For a small merchant, the practical consequence is that the annual self-assessment now requires someone technical in the room.

Your acquirer or payment provider will ask one question when they query the form. Show me how you know.

Which scripts count, and which ones your provider owns

The browser renders one page. Inside it, your provider serves the card fields in an iframe from its own domain. Scripts loaded by the provider inside that iframe sit in the provider’s scope. Everything the parent page loads sits in yours. That boundary is the whole of the argument, and it is narrower than most merchants assume.

The parent page still decides what code runs around the card fields. It controls the DOM the iframe sits in. It can be made to draw a convincing fake form over the top, or to read the name, address, email and phone number typed into your own fields, which is enough for card-not-present fraud when paired with details bought elsewhere. Hosted payment fields genuinely remove the card number from a skimmer’s reach. They do not end the obligation to know what your page loads.

The scripts that matter, in rough order of how often they cause trouble:

  • Tag managers, which load code you never reviewed and can be changed by someone outside IT
  • Analytics and conversion pixels, often several, often duplicated after an agency handover
  • Consent and cookie banner tools, which by design run before everything else
  • Chat and support widgets. A chat widget has no business on the page where card details are entered
  • Review, trust badge and A/B testing scripts, which inject markup into the page at runtime

Your delivery model sets the size of the job. A full redirect to a provider-hosted page, where no payment field is rendered inside your site, gives you the smallest scope. Provider-hosted fields embedded in your checkout put the parent page in scope. A card form on your own domain, posting to an API, is not SAQ A territory at all.

The evidence pack: what to assemble before you sign

A defensible answer is a dated folder, signed by a named person, with five things in it.

A script inventory. One row per script, with the source URL, what it does, why the business needs it on the checkout, the named owner, and the date it was authorised. File names alone are worthless here. Record what each script fetches at runtime, because a tag manager container is one line in your inventory and twenty scripts in the browser.

Authorisation records. The ticket, change request or email in which somebody with authority approved each script. Include the marketing tags added last quarter. If there is no record, create one now with today’s date and an honest note that the script predates the process.

Change detection output. Not a licence certificate. Actual alerts, with timestamps, and the action taken. Two or three real examples, including a false positive you investigated and closed, evidence the mechanism is live in a way a dashboard screenshot never does.

Configuration evidence. The live Content-Security-Policy response header captured from the payment page, the Subresource Integrity hashes in your templates, and screenshots of tag manager user permissions showing who can publish.

A short technical testing note. Half a page. What you tried in order to get an unauthorised script to run on the payment page, what happened, and what the policy blocked. This is the piece that turns a confirmation into a finding.

Building each control cheaply, without breaking checkout

Start with a Content Security Policy in report-only mode on the checkout page alone. Report-only breaks nothing. It tells the browser to send a JSON report to an endpoint you nominate whenever something would have been blocked.

A starting policy for a checkout using hosted fields looks roughly like this: script-src ‘self’ https://js.yourpsp.example https://www.googletagmanager.com; object-src ‘none’; base-uri ‘self’; frame-src https://js.yourpsp.example; report-uri /csp-report. Leave it for a fortnight, through a full billing cycle and at least one marketing campaign. Read the reports. The domains that surface are usually a consent tool nobody documented, a font or icon CDN, a review widget, a retired analytics pixel still firing, and one or two extensions belonging to your own staff’s browsers. Attribute each one, remove what you do not need, then switch the header to enforcing with a tight script-src. Our working CSP setup for a checkout page covers the nonce and hash mechanics.

Then pin the third-party scripts you cannot control. Subresource Integrity puts a cryptographic hash of the expected file in the script tag, and the browser refuses to execute anything that does not match. It is the strongest low-cost control on the list. It is also the one most likely to bite you. A supplier ships a routine update to its own hosted file, the hash no longer matches, the browser silently declines to load it, and your review widget or address lookup quietly disappears. Nobody reports it, because the page still looks fine.

So decide who watches for that breakage before you pin anything on a live checkout. The cheap version is a scheduled headless browser run, Playwright or Puppeteer on a cron job, that loads the checkout, asserts each expected script actually executed, and collects console errors. Run it every hour. Alert to the same place your uptime monitor alerts.

That same job gives you change detection for 11.6.1. Capture the list of loaded resource URLs and the response headers, sort them, hash the result, and store it. Diff against the previous run. Alert on any new domain, any header change, and any change to the hash of a script served from your own origin. Add your CSP report endpoint as a second, independent signal: a blocked script is by definition something that tried to load and was not authorised.

Mistakes that quietly void a PCI DSS SAQ A scripts claim

The iframe exemption is the most common error. The card fields being served by the provider does not make the parent page out of scope, because the parent still decides what loads around them.

Tag managers are the usual reason an honest answer goes stale. A marketing user with publish rights can put a script on the payment page in minutes. Your inventory is now wrong, and your CSP either blocks the tag, which causes an argument, or, if the policy allows the tag manager container broadly, permits whatever that container decides to load next. Restrict publish rights on the checkout container to two named people and require a change ticket. That single configuration change does more for eligibility than most monitoring products.

Inventorying files while ignoring what those files fetch at runtime is the second failure. So is treating the inventory as an annual document. A theme update, a platform upgrade or a new plugin can change the script set on a Tuesday afternoon, ten months after you signed the form.

Then there is first-party code. The three delivery routes the SAQ A wording is trying to close map neatly onto named incidents. Ticketmaster UK, 2018: a compromised third-party support script, for which the ICO fined the company £1.25 million in November 2020. British Airways, 2018: malicious code injected into the airline’s own first-party JavaScript, penalised with a £20 million ICO fine in October 2020. And the September 2020 Magento 1 event, where the security firm Sansec reported around 2,000 stores compromised over a single weekend, an unpatched platform exploited at scale with no third party involved at all. An inventory that lists only file names catches none of the three. The route each incident took into the checkout is the useful detail, not the size of the fine.

Keeping eligibility true for the next twelve months

Book thirty minutes a month. Diff the script inventory against what the headless run actually observed. Read the week’s CSP reports. Confirm change detection has fired at least once, even on a false positive, because a monitor that has been silent for six months is usually broken rather than reassuring.

Some events demand an out-of-cycle review: a new supplier widget, a replatform or theme change, a payment provider migration, a change of agency, or an issuer fraud report naming your site as a common point of purchase.

Be alert to the boundary too. If you find yourself explaining that the card fields are technically on your domain, or that a script on your page touches the payment data before it reaches the provider, you are in SAQ A-EP territory and the assessment is a larger piece of work. Say so early. It is cheaper than being corrected by an acquirer.

If change detection does fire on the payment page, capture before you clean. Save the rendered HTML, the resource list, the response headers and the suspect script file. Then remove the change, rotate admin credentials, and check the order data for the period concerned. The practical sequence is in our guide to telling whether a checkout has been skimmed.

The short version

The eligibility sentence is a confirmation, so build it into a folder: dated inventory with justifications and owners, authorisation records, real change detection alerts, the live CSP header, SRI hashes, a half-page testing note, and a signature. Report-only CSP first, then enforce. Pin what you can, and appoint someone to notice when a pinned script stops loading. Lock down who can publish to the checkout tag container. Do that and the PCI DSS SAQ A scripts claim is something you can defend, twelve months later, to somebody who asks how you know. If a supplier’s script is the one you are worried about, the supplier breach checkout checklist sets out twelve ordered steps for confirming whether it touched card data.

Frequently Asked Questions

Does using a payment provider iframe make my scripts exempt from SAQ A?

No. Scripts the provider loads inside its own iframe sit in the provider’s scope, but everything your parent page loads remains yours. The parent page can still be made to draw a fake payment form over the iframe or harvest name and address fields. The iframe narrows the target rather than removing the obligation.

Which scripts have to appear in a PCI DSS SAQ A script inventory?

Every script loaded and executed on the payment page as delivered to the customer’s browser. In practice that means your own JavaScript, tag manager containers and everything those containers load at runtime, analytics, consent tools, chat and review widgets, and any A/B testing code. Record the source, the business justification, the named owner and the authorisation date.

What evidence proves my payment page is not susceptible to script attacks?

Nothing proves it outright. What a reviewer will accept is a dated evidence pack: the script inventory with justifications, approval records, sample change detection alerts with the response taken, the live Content-Security-Policy header captured from the checkout, Subresource Integrity hashes, tag manager permission screenshots, and a short note describing what you tried in order to insert an unauthorised script and what blocked it.

Do requirements 6.4.3 and 11.6.1 apply to a small SAQ A merchant?

Both became mandatory on 31 March 2025 and appear in the SAQ A question set for merchants who embed the payment form in their own page. A full redirect to a provider-hosted payment page reduces what you must answer. Check the current version of SAQ A on the PCI SSC site, since the scoping wording has been clarified more than once.

What happens if I cannot answer the SAQ A script questions honestly?

Do not sign it. Speak to your acquirer, describe the gap and the timescale for closing it, and start with the cheapest fixes: move card inputs into provider-hosted fields, restrict tag manager publish rights, and run a report-only CSP on the checkout. A gap under remediation is a normal conversation. A false attestation is not.