---
key: "pci-dss-requirement-6"
title: "Map PCI DSS Requirement 6 to engineering practice and evidence"
url: "https://softwaresecurity.com/frameworks/pci-dss-requirement-6/"
api: "https://softwaresecurity.com/api/v1/articles/pci-dss-requirement-6.json"
domain: "governance"
topic: "Governance \u0026 frameworks"
type: "Guide"
identifiers: ["CWE-829","CWE-494","CWE-1395","A03:2025","A08:2025","V3.6","V15.1","V15.2"]
tags: ["Secure development lifecycle","Compliance and assurance evidence","Regulation"]
stages: ["govern"]
roles: ["appsec-engineer","platform-sre","security-leader"]
license: "CC-BY-4.0"
license_url: "https://creativecommons.org/licenses/by/4.0/"
code_license: "MIT"
---

# Map PCI DSS Requirement 6 to engineering practice and evidence

Turn PCI DSS v4.0.1 Requirement 6 into engineering work: secure development, review, patching, web-attack protection, payment-page script control and change management, with the records an assessor samples and the parts that became mandatory on 31 March 2025.

Canonical URL: https://softwaresecurity.com/frameworks/pci-dss-requirement-6/

## In short

Requirement 6 governs how you build and change systems that affect card data. Document procedures and owners (6.1). Build bespoke software to a secure SDLC, train developers every 12 months, review code before release and defend against common attacks (6.2). Track vulnerabilities, inventory your software and its components, and install critical patches within a month (6.3). Put automated attack protection in front of public web apps and control every payment-page script (6.4). Run changes through tested, approved procedures (6.5).

- Since 31 March 2025, 6.3.2 (software inventory), 6.4.2 (automated web-attack protection) and 6.4.3 (payment-page scripts) are fully assessed, with 11.6.1 tamper detection and its alert-response bullet in 12.10.5.
- Section 6.2 applies only to bespoke and custom software; the rest of Requirement 6 covers every in-scope system, and repositories holding code or configuration that can affect card data are in scope.
- A manual code review needs a reviewer other than the author, and release approval from someone accountable for releases who neither wrote nor reviewed the change.
- Install critical security patches within one month of release; set the windows for everything else from your own risk ranking.
- Embedding a payment provider's iframe doesn't take your page out of 6.4.3 and 11.6.1: the scripts around the iframe are yours, and in a single-page app every view counts.
- SAQ A dropped 6.4.3 and 11.6.1 in January 2025 but added an eligibility check on script attacks; the requirements themselves are unchanged.

## Recommended defaults

| Setting | Value | Note | Source |
| --- | --- | --- | --- |
| Developer security training | At least once every 12 months | Specific to job function and languages; include the security testing tools developers use. | PCI DSS v4.0.1 6.2.2 |
| Code review | Before release to production or to customers | Manual, automated or both. A manual review needs an independent reviewer and management approval. | PCI DSS v4.0.1 6.2.3, 6.2.3.1 |
| Critical security patches | Installed within one month of release | Critical as ranked by your 6.3.1 process. | PCI DSS v4.0.1 6.3.3 |
| Other security patches | Entity-defined, risk-based | The standard's guidance gives 60 days for high-risk and 90 days for others as an example, documented in a targeted risk analysis. | PCI DSS v4.0.1 6.3.3 guidance, 12.3.1 |
| Public-facing web applications | Automated solution in front that blocks attacks or alerts for immediate investigation | The yearly-assessment alternative in 6.4.1 ended on 31 March 2025. | PCI DSS v4.0.1 6.4.2 |
| Payment-page scripts | Authorized, integrity-assured and listed with a justification | Applies to the page that embeds a provider's payment iframe. | PCI DSS v4.0.1 6.4.3 |
| Payment-page change and tamper detection | At least weekly, or at a frequency set by a targeted risk analysis | Weekly means at least once every seven days. Covers security-impacting headers and script contents as the browser receives them. | PCI DSS v4.0.1 11.6.1, Table 4 |
| After a significant change | Confirm all applicable PCI DSS requirements; update documentation | — | PCI DSS v4.0.1 6.5.2 |

## Verify it

1. Sample recent production changes and trace each to a record with reason, security impact, approval, test results including the 6.2.4 checks, and a rollback plan.
2. Load the payment page and the page that embeds it in a headless browser and diff the scripts and security headers received against the inventory; every entry needs a justification and an approval reference.
3. In staging, change an approved script and remove the CSP header; confirm the monitor alerts the named owner and the alert is handled under the incident response plan.
4. Check training records: everyone who wrote bespoke or custom code in the past year, contractors included, was trained within the last 12 months on their languages and tools.
5. Pick a recent critical advisory for a component in your SBOM and show it was found, ranked and patched within one month of the patch's release.
6. Confirm a WAF or RASP sits in front of every public web app, in blocking mode or alerting into a queue someone works immediately, with current rules and retained logs.

## What you will learn

- Identify which Requirement 6 controls apply to each system and which became mandatory on 31 March 2025.
- Map each sub-requirement to an enforced practice and the evidence an assessor samples.
- Implement script authorization, integrity and inventory for a page that embeds a payment provider's iframe.
- Run a browser-based change and tamper check and route its alerts.

Audience: Engineering leads, AppSec engineers and platform teams who build or run software in scope for PCI DSS

Before you start:

- Know which systems are in, connected to or able to affect your cardholder data environment.
- Read a pull request workflow and a CI/CD deployment.
- Know what CSP and SRI do in a browser.

Time: About 36 minutes: 13 to read and 23 for the exercise

## What changed in PCI DSS v4.0.1 and on 31 March 2025?

PCI DSS v4.0.1, published in June 2024, is the only active edition; v4.0 was retired on 31 December 2024. The revision clarified wording without adding or removing requirements. Two clarifications touch Requirement 6: the one-month patch deadline in 6.3.3 again covers only critical vulnerabilities, and 6.4.3 now explains how it applies when your page embeds a payment provider's form. PCI SSC took comments on v4.0.1 in June and July 2026 for its next revision, so check the document library before each assessment.

The future-dated requirements that engineering owns or feeds became fully assessable on 31 March 2025:

| Requirement | Mandatory since 31 March 2025 | Note |
| --- | --- | --- |
| 6.3.2 | Inventory of bespoke and custom software and the third-party components built into it | Feeds vulnerability and patch management |
| 6.4.2 | Automated solution in front of public-facing web apps that detects and prevents attacks | Replaces 6.4.1, which also accepted a yearly application assessment |
| 6.4.3 | Authorization, integrity and a justified inventory for every payment-page script | Includes the page that embeds a provider's iframe |
| 11.6.1 | Change and tamper detection for security-impacting headers and scripts as the browser receives them | Weekly, or as your risk analysis justifies |
| 12.10.5, one bullet | The incident response plan covers alerts from the 11.6.1 mechanism | Each alert needs an owner and a playbook |
| 12.3.1 | A documented targeted risk analysis for each requirement that calls for one, such as a custom 11.6.1 frequency | Reviewed at least every 12 months |

## What does Requirement 6 cover?

Most of Requirement 6 applies to every system component in scope for PCI DSS. Section 6.2 is narrower. It covers bespoke software that a third party builds to your specification and custom software you build yourself, where it runs on a system in or connected to the cardholder data environment (CDE). Software you buy or download for general use is third-party software: 6.2 doesn't apply to it, but 6.3 still does.

Two scoping points catch engineering teams. Repositories holding application code or configuration that can affect the security of card data are in scope, so their access controls and history become evidence. And a payment page is any interface that captures card data, whether a whole page or a form in an iframe. Requirements 6.4.3 and 11.6.1 also reach the page that embeds a provider's iframe, because its scripts can tamper with what the shopper sees.

## Which practice and evidence answers each requirement?

The table paraphrases each requirement; the standard has the exact wording and testing procedures. Evidence means records an assessor can sample, not a policy statement alone.

| Requirement | Engineering practice | Evidence |
| --- | --- | --- |
| 6.1.1, 6.1.2 Procedures and roles | Versioned procedures for development, patching and change, each with a named owner | Current documents, a RACI, staff who can explain them |
| 6.2.1 Secure development | An SDLC based on a framework such as NIST SSDF, with PCI DSS needs like secure authentication and logging designed in | SDLC document; security requirements and threat models for recent features |
| 6.2.2 Training | Yearly training for everyone writing bespoke or custom code: their languages, secure design, the scanners they use | Training records per developer with dates and topics |
| 6.2.3, 6.2.3.1 Review before release | Reviewed pull requests and passing static analysis for every change; release approval by someone who neither wrote nor reviewed it | Ruleset settings, pull request approvals, release approvals |
| 6.2.4 Common attacks | Coding standards, framework defaults and tests for each listed attack class | Standard mapped to the classes; scanner rules; regression tests |
| 6.3.1 Vulnerability intake | Watch CERT, vendor and dependency advisories; rank findings, flagging high-risk and critical ones | Source list, ranking method, ranked findings |
| 6.3.2 Inventory | An SBOM for every release of bespoke and custom software, used to match advisories | SBOMs that match deployed versions |
| 6.3.3 Patching | Critical patches within a month of release; other windows set by risk | Install dates against vendor release dates; risk analysis |
| 6.4.2 Web-attack protection | WAF or RASP in front of every public web app, blocking or alerting into a monitored queue | Configuration, rule updates, logs, alert tickets |
| 6.4.3 Payment-page scripts | Justified inventory, approval workflow, SRI or CSP hashes, and a CSP that limits script and frame sources | Inventory, approval records, deployed headers and markup |
| 11.6.1 Tamper detection | Scheduled browser-based checks plus CSP violation reports that alert on new, changed or missing scripts and headers | Monitor configuration, monitored pages, results, handled alerts |
| 6.5.1 Change control | Each production change records reason, security impact, approval, tests including 6.2.4 checks, and a rollback path | Change records traced to deployments |
| 6.5.2 Significant change | A post-change checklist that re-confirms PCI DSS controls and updates diagrams | Completed checklists, updated diagrams |
| 6.5.3, 6.5.4 Separation | Separate pre-production accounts or networks; only the pipeline deploys to production, after approval | Network and IAM configuration, pipeline approval logs |
| 6.5.5, 6.5.6 Test data | Test card numbers only outside the CDE; test accounts and data removed before go-live | Test data samples, go-live checklist |

## How do you build the 6.2.4 attack classes into standards and tests?

6.2.4 lists the attacks your developers must prevent or mitigate in bespoke and custom code, and the assessor will ask how. Its guidance also calls out enumeration attacks such as card testing, so add rate limits and bot controls on payment endpoints to the same standard, and cover every class in the yearly 6.2.2 training. Give each class a technique, a test and the guide your team follows:

- Injection into SQL, LDAP, XPath, shell commands and other interpreters: parameterized APIs and argument arrays, with scanner rules and negative tests (/domains/appsec/secure-coding/injection-parser-boundaries/).
- Attacks on data and data structures, such as buffer and pointer manipulation: memory-safe languages where possible, bounded parsers, and fuzzing for native code (/domains/appsec/input-handling/bounded-json-xml-parsing/).
- Attacks on cryptography: vetted libraries and approved algorithms and modes, never home-made constructions (/domains/identity-crypto/encryption/crypto-quick-reference/).
- Business-logic abuse through APIs, client-side code or other functions, which the standard says includes XSS and CSRF: output encoding, CSRF defenses and server-side checks on every state change (/fix/xss/ and /fix/csrf/).
- Attacks on identification, authentication and authorization: deny-by-default checks on every object and function (/domains/appsec/authorization/object-level-authorization/).
- Any vulnerability your 6.3.1 process ranks high-risk: when a class keeps appearing in findings, add it to the standard and the test suite.

## How do you enforce review and release approval in the pipeline?

6.2.3 requires bespoke and custom code to be reviewed before it reaches production or customers, looking for existing and emerging vulnerabilities and fixing what it finds. Reviews can be manual, automated or both. When a person reviews, 6.2.3.1 adds two rules: the reviewer is not the author and knows secure code review, and management approves the change before release. Anyone formally accountable for release control who is neither the author nor the reviewer counts as management.

Encode those rules so nobody can skip them. The GitHub ruleset below requires a pull request, an approval of the latest push from someone other than the person who pushed it, code-owner review for paths you assign to trained reviewers in `CODEOWNERS`, and passing scanner checks. GitHub never lets authors approve their own pull requests. Create it with `gh api --method POST repos/OWNER/REPO/rulesets --input ruleset.json`. For release approval, make a release-manager team the required reviewers of the production environment, turn on prevent self-review, and record in each release that the approver wrote and reviewed none of the included changes.

```json
{
  "name": "payments-default-branch",
  "target": "branch",
  "enforcement": "active",
  "bypass_actors": [],
  "conditions": { "ref_name": { "include": ["~DEFAULT_BRANCH"], "exclude": [] } },
  "rules": [
    { "type": "deletion" },
    { "type": "non_fast_forward" },
    {
      "type": "pull_request",
      "parameters": {
        "required_approving_review_count": 1,
        "require_last_push_approval": true,
        "dismiss_stale_reviews_on_push": true,
        "require_code_owner_review": true,
        "required_review_thread_resolution": true
      }
    },
    {
      "type": "required_status_checks",
      "parameters": {
        "strict_required_status_checks_policy": true,
        "required_status_checks": [{ "context": "sast" }, { "context": "dependency-scan" }]
      }
    }
  ]
}
```

## How fast must vulnerabilities be ranked and patched?

6.3.1 asks for a process that watches industry sources, including national and international CERT alerts, and ranks each new vulnerability by potential impact so high-risk and critical issues stand out. It covers your own code and third-party software such as operating systems and databases. It comes on top of the internal and external scans in 11.3; scanning alone doesn't meet it. Put exploitation evidence, such as a CISA KEV listing, and the criticality of the affected system into the ranking.

6.3.2 makes the inventory explicit: list each bespoke and custom application and the third-party components inside it. An SBOM generated at build time and stored with each release (/domains/supply-chain/sbom/generate-release-inventory/) meets it and tells you within minutes whether you're affected. Under 6.3.3, critical patches go in within one month of their release, measured from the vendor's release date. Everything else follows your own risk-based timeline; the guidance gives 60 days for high-risk and 90 days for others as an example and recommends documenting the choice in a targeted risk analysis.

## What automated attack protection do public web apps need?

Until March 2025, 6.4.1 let you choose between a yearly application security assessment and an automated control. 6.4.2 removed the choice. Every public-facing web application now needs an automated technical solution in front of it that detects and prevents web attacks, stays running and up to date, writes audit logs, and either blocks attacks or raises alerts that someone investigates immediately. A WAF, on premises or in the cloud, is the usual answer; the guidance names RASP as another.

A WAF in detection-only mode that nobody watches fails the requirement. Keep penetration tests and dynamic scanning, which find flaws a WAF only hides, and use its rate limiting against brute-force and enumeration traffic.

## How do you control every script on the payment page?

6.4.3 covers every script that runs in the shopper's browser on a payment page, whether it comes from your servers, a third party or a party they load in turn. It needs three things: a way to confirm each script is authorized, a way to assure its integrity, and an inventory that says why each script is necessary. Vendor scripts can change before anyone approves them; the guidance accepts authorization confirmed as soon as possible after such a change.

If you embed a payment provider's iframe, the provider manages the scripts inside it and should evidence that in its own assessment. The scripts on your page around the iframe, including the provider's loader, are yours. PCI SSC's March 2025 e-skimming supplement adds three practical points: every view of a single-page app can reach the payment form, so all are in scope; you don't need to validate 6.4.3 for scripts that only perform 3-D Secure; and scripts from analytics or tag vendors that aren't payment service providers stay yours to manage.

Below, a checkout page embeds a provider's card fields. The CSP allows scripts only from your static host and the provider plus one inline script by hash, and limits frames to the provider. SRI pins your own bundle on the CDN, which must send CORS headers for the `crossorigin` attribute to work; compute the value with `openssl dgst -sha384 -binary checkout.3f9a1c.js | openssl base64 -A`. /tools/csp-evaluator/ checks a policy like this one for unsafe sources. Don't pin SRI on a script the provider updates in place: restrict its origin and monitor it instead.

```http
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Security-Policy: script-src https://static.shop.example https://js.psp.example 'sha256-9XnJEJhTJONL5rcPKccJc0GXVpI3ETVVRPS9VAjoqQo='; frame-src https://js.psp.example; connect-src 'self' https://api.psp.example; form-action 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'; report-uri /csp-reports; report-to csp
Reporting-Endpoints: csp="https://shop.example/csp-reports"
Strict-Transport-Security: max-age=63072000; includeSubDomains
X-Content-Type-Options: nosniff

<!doctype html>
<title>Checkout</title>
<script>window.checkoutConfig = { currency: "EUR", locale: "de-DE" };</script>
<script src="https://static.shop.example/checkout.3f9a1c.js"
        integrity="sha384-d21gsES0lxhCd1QdFSJcdTEQq+Wzb3VZx7pO9SmOoCFhWZ3uX2UsE5NwydmKSXTR" crossorigin="anonymous"></script>
<form action="/orders" method="post">
  <div id="card-fields"><!-- the PSP loader adds its card-field iframe here --></div>
  <button>Pay</button>
</form>
<script src="https://js.psp.example/v3/fields.js"></script>
```

## Where should the payment-page script inventory live?

Store the inventory next to the code that loads the scripts, so adding a script takes a reviewed change with a justification and an approval reference. The same file is the baseline for 11.6.1. Hashes are base64 SHA-256 digests in CSP notation; for the inline script it is exactly the value in the CSP header. Header names are lower case, as the browser reports them.

```json
{
  "page": "https://shop.example/checkout",
  "owner": "payments-web on-call",
  "headers": {
    "content-security-policy": "script-src https://static.shop.example https://js.psp.example 'sha256-9XnJEJhTJONL5rcPKccJc0GXVpI3ETVVRPS9VAjoqQo='; frame-src https://js.psp.example; connect-src 'self' https://api.psp.example; form-action 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'; report-uri /csp-reports; report-to csp",
    "strict-transport-security": "max-age=63072000; includeSubDomains",
    "x-content-type-options": "nosniff"
  },
  "scripts": [
    {
      "src": "inline",
      "hash": "sha256-9XnJEJhTJONL5rcPKccJc0GXVpI3ETVVRPS9VAjoqQo=",
      "justification": "Sets currency and locale for the checkout UI",
      "approval": "CHG-2291"
    },
    {
      "src": "https://static.shop.example/checkout.3f9a1c.js",
      "hash": "sha256-VJJaPt7b65aiGQLQ5te0mHJAQQjTiGjtp9SqyZd7urA=",
      "justification": "Checkout UI bundle built by our pipeline",
      "approval": "CHG-2291"
    },
    {
      "src": "https://js.psp.example/v3/fields.js",
      "hash": "sha256-35N3xlFEtYewldTV+ezv0M4XToHVHTisROw0l34PCpQ=",
      "justification": "PSP loader that inserts the card-field iframe; the PSP updates it, so re-approve on change",
      "approval": "CHG-2104"
    }
  ]
}
```

## How do you detect changes the way the browser sees the page?

11.6.1 asks for a mechanism that alerts staff to unauthorized changes, additions and deletions in the security-impacting HTTP headers and the script contents of payment pages as the browser receives them. It must run at least weekly or at a frequency your targeted risk analysis justifies. File monitoring on the server can't see what a tag manager or a compromised third party injects, so test what the browser gets. The standard's examples include CSP violation reports, synthetic monitoring, tamper-detecting scripts and checks at a proxy or CDN, and no single one is complete.

The script loads the page in headless Chromium with Playwright and compares the scripts and headers it receives with the inventory. It ignores scripts inside the provider's iframe and reports scripts the CSP blocked, so a blocked injection still raises an alert. Run it hourly, and script the checkout steps if the payment form is a view in a single-page app. CSP reports cover real shoppers' browsers between runs. Route failures to the owner on call and handle them under the incident response plan, as 12.10.5 requires.

```js
// Compare the checkout page a browser receives with the approved inventory.
// Usage: node check-payment-page.mjs https://shop.example/checkout inventory.json
import { createHash } from 'node:crypto';
import { readFile } from 'node:fs/promises';
import { chromium } from 'playwright';

const [pageUrl, inventoryFile] = process.argv.slice(2);
const inventory = JSON.parse(await readFile(inventoryFile, 'utf8'));
const sha256 = (data) => 'sha256-' + createHash('sha256').update(data).digest('base64');

const browser = await chromium.launch();
const page = await browser.newPage();
const topLevel = (res) => { try { return res.frame() === page.mainFrame(); } catch { return false; } };
const fetched = []; // scripts the parent page loads; scripts inside the PSP iframe are the PSP's
page.on('response', (res) => {
  if (res.request().resourceType() !== 'script' || !topLevel(res)) return;
  fetched.push(res.body().then(sha256, () => 'unreadable').then((hash) => ({ src: res.url(), hash })));
});
const doc = await page.goto(pageUrl, { waitUntil: 'networkidle' });
const headers = await doc.allHeaders(); // lower-case names
const elements = await page.$$eval('script', (els) => els.map((e) => ({ src: e.src, text: e.text })));
await browser.close();

const seen = await Promise.all(fetched);
for (const { src, text } of elements) {
  if (!src) seen.push({ src: 'inline', hash: sha256(text) });
  else if (!seen.some((s) => s.src === src)) seen.push({ src, hash: 'not loaded' }); // e.g. blocked by CSP
}

const alerts = [];
const same = (a, b) => a.src === b.src && (a.src !== 'inline' || a.hash === b.hash);
for (const s of seen) {
  const approved = inventory.scripts.find((a) => same(a, s));
  if (!approved) alerts.push(`NEW script ${s.src} ${s.hash}`);
  else if (approved.hash !== s.hash) alerts.push(`CHANGED script ${s.src} ${s.hash}`);
}
for (const a of inventory.scripts) {
  if (!seen.some((s) => same(a, s))) alerts.push(`MISSING script ${a.src}`);
}
for (const [name, value] of Object.entries(inventory.headers)) {
  if (headers[name] !== value) alerts.push(`CHANGED header ${name}: ${headers[name] ?? '(absent)'}`);
}
console.log(alerts.join('\n') || `OK ${seen.length} scripts, ${Object.keys(inventory.headers).length} headers`);
process.exitCode = alerts.length ? 1 : 0; // non-zero: page the owner named in the inventory
```

## How does the pipeline serve as change control?

6.5.1 expects every production change to record its reason, security impact, approval, test results and a way back to a secure state, and bespoke code changes must be tested against the 6.2.4 attack classes before deployment. A pull request linked to a ticket, scanner results, an approved deployment and a tested rollback cover this, provided nobody can deploy outside the pipeline. After a significant change, 6.5.2 asks you to confirm every applicable PCI DSS control on new or changed systems and update the documentation.

Separate pre-production from production with enforced access controls (6.5.3), and split roles so only reviewed and approved changes reach production (6.5.4); a developer can hold admin rights in development if their production access is limited. Never use live card numbers in pre-production outside the CDE (6.5.5), and remove test accounts and test data before a system goes live (6.5.6).

## Guided practice

Fernhill Outdoor (fictional) has its first PCI DSS v4.0.1 assessment since the future-dated requirements took effect. Review the readiness notes below and list each gap by requirement, with the evidence that shows it and the fix.

### Supplied material

```text
Assessment date 2026-11-02. Checkout embeds the PSP card-field iframe from js.psp.example.
P1 Scripts a headless browser receives on /checkout (parent page):
   static.fernhill.example/app.4c2e.js (first party), js.psp.example/v3/fields.js (PSP loader),
   tags.example/gtm.js (tag manager), chat.example/widget.js (support chat, loaded by the tag manager)
P2 Inventory lists app.4c2e.js, fields.js and gtm.js with justifications; no approval records; no SRI attributes.
P3 Headers: Content-Security-Policy-Report-Only: script-src 'self' 'unsafe-inline' *.example; no enforced CSP.
P4 Evidence offered for 11.6.1: the quarterly external ASV scan.
P5 WAF in front of www and checkout runs in detect-only mode; alerts go to a shared mailbox with 312 unread.
P6 Ruleset: 1 approval, require_last_push_approval false. Any maintainer approves production deploys;
   in 2 of 10 sampled releases the approver also reviewed an included pull request.
P7 OpenSSL fix ranked critical, released 2026-08-04, installed on the checkout API hosts 2026-09-15.
P8 Training: 9 of 11 in-house developers trained in the last 12 months; the 2 agency contractors who build
   the bespoke loyalty service (runs in the CDE) have never been trained.
P9 SBOMs exist for checkout-api and checkout-web, none for the loyalty service.
```

### 1. Scope the scripts

Decide which scripts in P1 fall under 6.4.3 and 11.6.1, and judge P2 and P3 against 6.4.3.

Worked answer: All four run on the page that embeds the iframe, so all are Fernhill's; scripts inside the PSP iframe are the PSP's. The chat widget is missing from the inventory, nothing records authorization, and a report-only CSP with `'unsafe-inline'` and a wildcard enforces no integrity. Fix: approve or remove each script, enforce a CSP with exact origins and hashes, add SRI to `app.4c2e.js`, and consider keeping the tag manager off checkout.

### 2. Judge the tamper detection

Decide whether P4 meets 11.6.1 and what to add.

Worked answer: No. An ASV scan doesn't evaluate the headers and scripts the browser receives on the payment page. Add a browser-based check at least weekly (hourly is better) plus CSP reports, alerting a named owner, and add those alerts to the incident response plan for 12.10.5.

### 3. Judge the WAF

Decide whether P5 meets 6.4.2.

Worked answer: No. The solution must block attacks or raise alerts that are investigated immediately; an unread mailbox does neither. Switch tuned rules to blocking and route the rest to a queue the on-call team works.

### 4. Check review and release

Evaluate P6 against 6.2.3.1.

Worked answer: Two sampled releases fail: release approval must come from someone who neither wrote nor reviewed the change. With last-push approval off, whoever pushes the final commit can also approve it, so code can merge without independent review. Enable `require_last_push_approval`, make a release-manager team the environment reviewers with prevent self-review on, and add a release check that the approver isn't an author or reviewer.

### 5. Check patching, training and inventory

Evaluate P7, P8 and P9.

Worked answer: P7 took 42 days, past the one-month limit in 6.3.3. P8 fails 6.2.2: agency developers building bespoke software in the CDE are software development personnel and need yearly training. P9 fails 6.3.2: the loyalty service and its components must be in the inventory.

Deliverable: A gap list keyed by requirement number, each line giving the evidence that shows the gap, the fix and an owner.

Scope: Paper exercise with a fictional company. The answers follow PCI DSS v4.0.1 and the March 2025 supplement; your assessor and acquirer decide validation scope and which SAQ, if any, applies.

Articles and teaching material: CC BY 4.0. Original executable code: MIT. Attribution: Software Security.

## Sources

- [PCI SSC document library: PCI DSS v4.0.1 and the v4.0 to v4.0.1 summary of changes](https://www.pcisecuritystandards.org/document_library/?category=pcidss&document=pci_dss). v4.0.1 (June 2024).
- [PCI SSC: Important updates announced for merchants validating to SAQ A (January 2025)](https://blog.pcisecuritystandards.org/important-updates-announced-for-merchants-validating-to-self-assessment-questionnaire-a)
- [PCI SSC: Payment Page Security and Preventing E-Skimming information supplement (March 2025)](https://blog.pcisecuritystandards.org/new-information-supplement-payment-page-security-and-preventing-e-skimming)
- [PCI SSC: Request for comments on PCI DSS v4.0.1 (3 June to 20 July 2026)](https://blog.pcisecuritystandards.org/request-for-comments-pci-data-security-standard-pci-dss-v4.0.1)
- [W3C Subresource Integrity](https://www.w3.org/TR/sri/). W3C Working Draft, 20 March 2026.
- [W3C Content Security Policy Level 3: hash sources](https://www.w3.org/TR/CSP3/#grammardef-hash-source). W3C Working Draft, 16 September 2026.
- [GitHub REST API: create a repository ruleset](https://docs.github.com/en/rest/repos/rules#create-a-repository-ruleset)
- [GitHub Docs: deployment environments, required reviewers and self-review](https://docs.github.com/en/actions/reference/workflows-and-actions/deployments-and-environments#required-reviewers)
- [Playwright: Response class (frame, body, allHeaders)](https://playwright.dev/docs/api/class-response)