Control template: PCI DSS v4.0
Status: Stable · Version: pci-dss-v4/v1.0.0
A bundle of CALM control snippets covering the architectural surface
of PCI DSS v4.0. You copy these into your *.calm.json files on the
nodes that handle cardholder data (the Cardholder Data Environment,
or CDE).
This replaces the legacy framework-gated validators that fired
automatically when a node declared compliance-frameworks: ["pci"].
Why the change:
- You author what you want enforced. No surprise "ArchRails decided your service was PCI-scoped"; you decide.
- You control the rule vocabulary. Findings on the PR comment read in your language ("encryption-at-rest on cardholder-db"), not ours.
- Versioned. Pin to
v1.0.0; upgrade tov2.0.0(PCI v5 when it ships) on your schedule. - Cleaner audit story. "Customer policy as authored, enforced by ArchRails" reads better in an audit than "ArchRails opinion imposed."
What this template covers
5 of PCI DSS v4.0's 12 high-level requirements are addressed architecturally below by code-enforcing controls. The remaining ones (Req 1 segmentation, Req 5 anti-malware, Req 6 WAF, Req 8 MFA, Req 9 physical, Req 11 testing, Req 12 incident response, plus Req 10 audit-logging field declarations) are process, declared-only, or endpoint-detection territory — pair ArchRails with Crowdstrike / SentinelOne / your QSA program for those surfaces.
| PCI DSS v4 Requirement | Control alias below |
|---|---|
| Req 2 — Secure configurations (no default credentials) | pci-no-default-credentials |
| Req 3 — Stored account-data encryption | pci-data-encryption-at-rest |
| Req 4 — Strong cryptography in transit | pci-no-unsafe-protocol |
| Req 7 — Access restrictions (RBAC) | pci-rbac-required |
| Req 10 — Log retention | pci-log-retention |
The CDE pattern
A node belongs to the Cardholder Data Environment (CDE) if it stores, processes, or transmits cardholder data. Tag those nodes explicitly in your CALM:
{
"unique-id": "payments-api",
"node-type": "service",
"name": "Payments API",
"metadata": {
"cde": true,
"data-classification": "pci"
}
}
Then attach the relevant controls below.
pci-data-encryption-at-rest, pci-log-retention.
Control snippets
Copy each block under the controls key of the node it applies to.
Req 2 — No default credentials (pci-no-default-credentials)
Gap-filler new in this template. PCI DSS v4 Req 2.2 requires that
vendor-default credentials are removed or changed before deployment.
Architecturally: forbid hard-coded patterns like admin/admin,
root/changeme, postgres/postgres, etc.
"pci-no-default-credentials": {
"description": "PCI DSS v4 Req 2.2 — vendor-default credentials must not appear in code or config.",
"requirements": [
{
"requirement-url": "https://archrails.io/catalog/req/pci-dss-v4/no-default-credentials",
"config": {
"control-id": "pci-no-default-credentials",
"forbidden-fields": [
"admin:admin",
"admin:password",
"root:root",
"root:changeme",
"postgres:postgres",
"mysql:mysql",
"guest:guest",
"test:test"
]
}
}
]
}
Req 3 — Data encryption at rest (pci-data-encryption-at-rest)
Stored cardholder data must be encrypted at rest. Declare which algorithm + key-management approach this node uses.
"pci-data-encryption-at-rest": {
"description": "PCI DSS v4 Req 3.5.1 — stored cardholder data must be encrypted with industry-standard algorithms.",
"requirements": [
{
"requirement-url": "https://archrails.io/catalog/req/pci-dss-v4/data-encryption-at-rest",
"config": {
"control-id": "pci-data-encryption-at-rest",
"algorithm": "AES-256-GCM",
"key-management": "aws-kms-cmk",
"key-rotation-days": 365
}
}
]
}
Req 4 — No unsafe protocol (pci-no-unsafe-protocol)
Relationship-level control. Attach to edges that touch CDE nodes; the engine forbids the listed plaintext protocols on those edges.
// On a relationship (NOT a node):
"controls": {
"pci-no-unsafe-protocol": {
"description": "PCI DSS v4 Req 4.2.1 — CHD transmission must use strong cryptography. Plaintext protocols forbidden on CDE-touching edges.",
"requirements": [
{
"requirement-url": "https://archrails.io/catalog/req/pci-dss-v4/no-unsafe-protocol",
"config": {
"control-id": "pci-no-unsafe-protocol",
"forbidden-fields": [
"http", "ftp", "telnet", "ws",
"smtp", "imap", "pop3", "ldap",
"rsh", "rlogin", "tftp",
"amqp", "mqtt", "redis", "nats"
]
}
}
]
}
}
Req 7 — RBAC (pci-rbac-required)
Gap-filler new in this template. PCI DSS v4 Req 7 requires need-to-know access restrictions. Architecturally: declare which roles can reach this node and through which authentication patterns.
"pci-rbac-required": {
"description": "PCI DSS v4 Req 7.2 — access to CDE restricted by role / need-to-know.",
"requirements": [
{
"requirement-url": "https://archrails.io/catalog/req/pci-dss-v4/rbac-required",
"config": {
"control-id": "pci-rbac-required",
"authentication-pattern": "oauth2-bearer",
"allowed-roles": ["payments-admin", "payments-service"],
"principle": "least-privilege"
}
}
]
}
Req 10 — Log retention (pci-log-retention)
"pci-log-retention": {
"description": "PCI DSS v4 Req 10.5.1 — audit logs retained for at least 12 months, with 3 months immediately available.",
"requirements": [
{
"requirement-url": "https://archrails.io/catalog/req/pci-dss-v4/log-retention",
"config": {
"control-id": "pci-log-retention",
"retention-days": 365,
"hot-tier-days": 90
}
}
]
}
What the engine actually enforces
The legacy PCI-framework validators that fired automatically when a node declared compliance-frameworks: ["pci"] were retired 2026-05-27 as part of the broader templatization shift. Today's enforcement is entirely graph-driven: you attach a control where you want it enforced, and the absence of an attach is opt-out by silence. There is no PCI-specific cross-cutter — the engine has no "if cde: true, require these controls" sweep.
For the PCI DSS v4 controls above, here is the honest split:
Enforced via attestation (constraint engine)
Every snippet's config block is read by the constraint engine: presence / exact / enum / set_required / set_forbidden shapes are inferred from what you authored, and the agent's declared_pattern must satisfy them. This applies to every snippet's value-level checks (TLS version, encryption algorithm, retention days, MFA factor count, etc.) regardless of category.
Enforced via sensitivity-gated validators (separate path)
When a node declares data-classification: pci (or pii / phi), a set of always-on architectural validators fires on changes to that node's code — independent of which PCI controls you've authored. These cover:
- Secret detection — substantive enforcement for
pci-no-default-credentials(broader credential dictionary than the snippet) - Weak crypto — weak/deprecated algorithms on PII/PCI/PHI nodes
- Authorization — sensitive nodes must have an authz layer
- Edge protocol — plaintext protocols on edges touching a PCI-classified node
- Sensitive fixture detection — real-looking PII/PHI/PCI literals committed to governed files
- Retention — required retention windows on PII/PCI/PHI data stores
And the diff-walking AR-REL-008 validator fires on any outbound call from a PCI-classified node to an external host that the node's allowed_connects doesn't declare — substantive enforcement for the pci-no-unsafe-protocol snippet's TLS-only-on-CDE-edges intent.
Documentation / audit metadata
These snippets carry the regulatory tag for audit pivot but no engine enforcement on code changes:
- All URL-typed fields across the template (policy URLs).
All checks are deterministic — pure function over your CALM JSON. Verdicts are replayable byte-for-byte. The same constraint engine handles GDPR, SOC 2, HIPAA, MiFID II, ISO 27001:2022, NIST CSF 2, NYDFS Part 500, and any controls you author yourself.
Versioning
This is pci-dss-v4/v1.0.0 — the first stable cut. Each surviving control has per-validator firing tests + cross-language coverage across 11 Tier A languages (Python, Java, C#, TypeScript, Go, Kotlin, Scala, Rust, Ruby, Swift, PHP). Future bumps: v1.x.y for additive controls and substantive validator coverage; v2.0.0 for breaking changes (control retired, semantics changed). Updates as authoritative guidance or enforcement priorities materially shift.