Payment-page script authorization
PCI DSS 4.0 requirement 6.4.3 asks that every script on a payment page is authorized, that its integrity is assured, and that an inventory records why it is needed. HeaderHawk keeps the decision itself. A named person authorizes or rejects each script and writes down why, and no later decision overwrites an earlier one.
A Content Security Policy lists the hosts a page may load scripts from. It is the control, and it belongs in front of every checkout. It does not record who approved a script, what they looked at, or why the page needs it, and an assessor asks all three.
- Plans
- The Professional and Business plans
- In the dashboard
- Scripts › Payment pages
What's at stake
An allowlist is not a decision
Most teams can show which hosts their checkout may load from. Far fewer can show who decided each script belonged there, and what it was when they decided.
No record
The policy says where, not who or why
A host added to script-src last spring is still there, and nobody remembers the ticket. When the assessor asks why each script is there, the policy has no answer.
Unannounced change
The approved script is not the same file any more
Vendors ship to the same URL. An approval of js.vendor.com in March says nothing about the bytes your customers ran in September, and neither does the policy that allowed it.
Gone by audit
The version you decided about has been replaced
When someone asks what was in that file on the day, the origin serves today's version, and nobody kept the old one.
What it does
A decision per script, kept like evidence
Authorize or reject, and say why
Every script browsers report on your payment pages, and every script the daily scan finds in their HTML, arrives in a review queue. Someone authorizes or rejects it and gives a reason. A decision with no justification is refused, so every approval in the inventory can be explained.
Members and above decide, and every role, viewers included, can read the decisions. A justification can run to 2,000 characters, room for a paragraph an assessor can follow.
Script URL https://js.stripe.com/v3/
Status authorized
Integrity mode any_content
Justification Stripe Elements renders the card fields in
an iframe. Required by our payment provider;
reviewed with the payments team.
Decided by A. Rivera
Decided at 2026-09-18T14:02:11Z
Seen by browsers and scan
First seen 2026-08-02T09:15:40ZPin the versions you reviewed, or accept the URL
Each authorization has an integrity mode. Pin up to 50 hashes you reviewed, and any other version is flagged as a change. Or accept any content from the URL, which suits a vendor that ships several times a week, and new versions raise no alert.
Every hash a script has been seen with is listed beside it, marked as reported by browsers, found by the daily scan, or both.

An append-only history
Decisions are append-only. The newest becomes the script's status, and every earlier one stays, with who made it and when. Moving to a smaller plan keeps the record. A team that has made decisions can still read, filter and export them.
The inventory exports as CSV, one row per script and payment page, with the library each hash was identified as, its advisories, the decision, its justification, who made it and when. The file opens by saying what it cannot show.
# This is what browsers reported and what HeaderHawk's
# daily scan of each payment page found. It is not proof
# that nothing else ran.
Payment page,Page pattern,Script URL,Library,
Library version,Identification,Advisories,
Advisory IDs,Worst severity,Fixed in,Status,
Integrity mode,Pinned hashes,Hashes seen,
Justification,Decided by,Decided by email,
Decided at,First seen,Last seen,Seen by,
Last scanned,Gone from page (last found)Alerts when a payment page's scripts change
A script new to the site running on a payment page, an unpinned version of a pinned script, or a rejected script running again raises an alert through your rules. Anyone can post a report, so these wait until browsers on two different networks have reported the script within 24 hours, or until the page's daily scan fetches it, which alerts on that scan. A site gets at most five new or changed script alerts an hour, then one summary.
The daily scan also reports when a script has left a payment page, and when it seems to have moved host, a pairing by file name that the alert calls a guess. Both come from what the scan found, never from browsers going quiet. A site's first day and a page's first scan set the baseline without alerting.
New script on a payment page
Pinned script changed
Rejected script seen again
Script gone from a payment page
Script moved to another originThe file behind the decision, kept
When a new version of a payment-page script appears, HeaderHawk fetches it once and keeps the file only if its SHA-256 matches the reported hash, so the copy is the code your visitors ran. Owners and admins can download it from the script's page. Every download is recorded, and copies are kept for twelve months.
The fetch is never retried. A file changed or removed before the fetch is recorded as a mismatch, with the fingerprint of what was served instead, and no copy is kept. A short-lived injected payload usually ends up here, and the record says so.
Known vulnerabilities next to the decision
Where a script's hash identifies a library version, the advisories published against that version appear beside the decision, with their severity and the release that fixes them. A high or critical one raises an alert once. The check runs every day, so a script authorized months ago still meets an advisory published this morning.
The 6.4.3 answer, on every plan
The dashboard's Compliance page reads these records for one site and says whether 6.4.3 is met, partially met or not met, with the facts behind the verdict and what is missing. It is a readiness view, not an attestation. The PCI DSS page sets out which parts of 6.4.3 and 11.6.1 the browser layer covers.
How it runs
One keyword in your policy. Nothing on the checkout page.
A site's setup panel writes the headers for the report types you switch on. With script hashes on, the policy gains one keyword:
Reporting-Endpoints: headerhawk="https://k3x9mp2nq7ab.ingest.us.headerhawk.com/r"
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' 'report-sha256'; report-uri https://k3x9mp2nq7ab.ingest.us.headerhawk.com/r; report-to headerhawk- The hashes come from 'report-sha256' in your script-src, which asks Chrome and Edge to report each script they fetch. It allows and blocks nothing.
- No agent, SDK, tag or proxy goes on the payment page, so none of our code runs on the page you are keeping clean.
- The daily scan fetches each payment page once from our infrastructure, never through your visitors.
- A decision is recorded, not enforced. Your policy and your deploys decide what runs, and the record shows what you decided.
Scope
One layer, and where it stops
Authorization is the record half of 6.4.3. The control half is your policy and the integrity attributes on your tags, which the browser enforces. A rejected script runs until your site or your policy stops it. The inventory shows what browsers reported and the scan found, which is not proof that nothing else ran.
| Script authorization does | It does not replace |
|---|---|
| Records who authorized or rejected each payment-page script, when, and why | Your Content Security Policy, which stops an unapproved script loading |
| Pins the versions you reviewed, and alerts on one you did not | Subresource Integrity on the tag, which stops a changed file running |
| Keeps a verified copy of new versions it could fetch unchanged | Threat intelligence on script hosts. HeaderHawk records decisions and does not score domains |
| Exports the inventory and its decisions as CSV for your assessor | Your QSA's judgement, since a readiness view is not an attestation |
Put a reason next to every script
Script authorization is on the Professional and Business plans. Mark your checkout as a payment page and the review queue fills from the next report.