---
title: "Guard every script on a payment page · Agent Wranglers"
url: https://agentwranglers.se/playbook/payments/card-security-and-sca/payment-page-scripts
id: PAY-76
level: Required
applies: payments
risk: data
updated: 2026-10-27
build: a2a6bdfed830
tokens: 1359
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Guard every script on a payment page

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Card security and SCA](https://agentwranglers.se/playbook/payments/card-security-and-sca.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-27.

- ID: PAY-76
- Level: Required
- Chapter: [Card security and SCA](https://agentwranglers.se/playbook/payments/card-security-and-sca.md)
- Rule: On every page that shows card fields or the provider's payment iframe, allow only scripts on a written inventory. Detect any change to those scripts or the page's security headers within 7 days, and alert.
- Check: The repository holds the script inventory with a reason for each entry. A scheduled job ran in the last 7 days and loaded each payment page in a headless browser. It found only inventoried scripts and the approved headers. Adding a test script to the staging payment page makes the next run alert.
- Risk: Data leaked or lost
- Applies when: The project takes payments.
- How: PCI DSS v4.0.1 requirements 6.4.3 and 11.6.1 have applied since 31 March 2025. Requirement 6.4.3 asks that each script on a payment page is authorised, has its integrity checked and sits on an inventory with a reason. Requirement 11.6.1 asks for a mechanism that alerts on unauthorised changes to the scripts and HTTP headers the browser receives, run at least weekly. Both apply in full under SAQ A-EP and SAQ D. Under SAQ A, an eligibility criterion for pages that embed the provider's iframe replaces the old line items. See [Choose a checkout that keeps you on SAQ A](https://agentwranglers.se/playbook/payments/card-security-and-sca/pci-saq-a-integration.md) says. A plain redirect to a hosted page is outside both. Build the allow list as a [Content Security Policy](https://agentwranglers.se/playbook/application-security/browser-security-headers/content-security-policy.md) with a report address. Pin fixed third-party files with [Subresource Integrity](https://agentwranglers.se/playbook/application-security/browser-security-headers/subresource-integrity.md). Then run a scheduled browser job that loads the payment page, lists every script and header, and compares them with the approved list. Card skimming attacks such as Magecart inject one extra script, so the job must fail on any new source.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### JavaScript example

```js
// Playwright: every script on the payment page is on the approved inventory
import inventory from './payment-page-scripts.json' with { type: 'json' }

test('payment page loads only inventoried scripts', async ({ page }) => {
  const loaded = []
  page.on('request', request => { if (request.resourceType() === 'script') loaded.push(new URL(request.url()).origin + new URL(request.url()).pathname) })
  const response = await page.goto('https://example.com/checkout')
  expect(loaded.filter(src => !inventory.scripts.includes(src))).toEqual([])
  expect(response.headers()['content-security-policy']).toBe(inventory.contentSecurityPolicy)
})
```

### Python example

```python
# Playwright for Python: the same weekly check
import json
from urllib.parse import urlsplit

INVENTORY = json.load(open("payment-page-scripts.json"))

def test_payment_page_loads_only_inventoried_scripts(page):
    loaded = []
    page.on("request", lambda r: r.resource_type == "script" and loaded.append(
        "{0.scheme}://{0.netloc}{0.path}".format(urlsplit(r.url))))
    response = page.goto("https://example.com/checkout")
    assert [src for src in loaded if src not in INVENTORY["scripts"]] == []
    assert response.headers["content-security-policy"] == INVENTORY["contentSecurityPolicy"]
```

## Sources

- [PCI SSC document library with PCI DSS v4.0.1](https://www.pcisecuritystandards.org/document_library/)
- [W3C Content Security Policy Level 3](https://www.w3.org/TR/CSP3/)

## Related rules

- PAY-1 [Choose a checkout that keeps you on SAQ A](https://agentwranglers.se/playbook/payments/card-security-and-sca/pci-saq-a-integration.md) in Payments and billing
- APS-25 [Allow only the scripts you wrote](https://agentwranglers.se/playbook/application-security/browser-security-headers/content-security-policy.md) in Application security
- APS-33 [Lock scripts to a known hash](https://agentwranglers.se/playbook/application-security/browser-security-headers/subresource-integrity.md) in Application security

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/payments/card-security-and-sca/payment-page-scripts">Agent Wranglers payments and billing playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Choose a checkout that keeps you on SAQ A](https://agentwranglers.se/playbook/payments/card-security-and-sca/pci-saq-a-integration.md)
- Next: [Handle 3-D Secure in every card flow](https://agentwranglers.se/playbook/payments/card-security-and-sca/strong-customer-authentication.md)
- [Card security and SCA](https://agentwranglers.se/playbook/payments/card-security-and-sca.md)
