Compliance Frameworks
Trace PCI DSS v4.0.1 requirements and OWASP LLM risks to Chio records, and build the evidence package every mapping draws on.
On this page
Two lists meet at an agent's tool calls: PCI DSS v4.0.1, which asks a cardholder-data operator to grant access by need to know, authenticate accounts, and protect its audit logs, and the OWASP Top 10 for LLM Applications, which names the risks an LLM application must answer. For each governed call, the kernel signs a record of its decision, and an assessor checks those records offline against either list.
Mapped against PCI DSS v4.0.1 and the OWASP LLM Top 10 (2025 edition), reviewed 10 September 2026. The rows are selected technical mappings. PCI DSS rows use v4.0.1, which replaces the retired v4.0; OWASP rows use the 2025 taxonomy by name.
Each row reads requirement, technical contribution, operator action, evidence. A signature proves who signed and binds the recorded content; the truth of a business claim and the completion of an organizational process stay with the operator. Build and verify an evidence package.
Req 1.3: inbound and outbound traffic restricted
Inbound and outbound traffic is restricted. egress_allowlist limits the targets an agent reaches, at the application layer beside network ACLs. Answered by the guard pipeline.
Operator. Keep network-layer ACLs; the egress guard sits beside them.
Read the mapping in Compliance frameworks.
PCI DSS requirements meet the agent at its tool calls
PCI DSS v4.0.1 protects cardholder data and sensitive authentication data across people, processes, and technology. Chio holds no card data itself; the agents it governs call the payment gateways and CRMs that do, and the kernel decides which of those tools an agent may reach and under which conditions.
| Requirement | Chio control | Evidence record | Owner |
|---|---|---|---|
Req 1.3 | Egress allowlist guard | GuardEvidence | Chio and operator |
Req 6.5 | Policy hash | policy_hash | Chio |
Req 7.2 | Capability scope, grant constraints | CapabilityToken | Chio |
Req 7.2.5 | Least-privilege capabilities | CapabilityToken | Chio |
Req 7.3 | Issuance and revocation | Deny receipt after revocation | Chio |
Req 8.2 | Agent identity | Workload | Chio |
Req 8.3 | DPoP binding | DPoP proof | Chio |
Req 8.6 | Expiry and revocation | expires_at, deny receipt | Chio |
Req 10.2 | Signed receipts | ChioReceipt | Chio |
Req 10.3 | Merkle checkpoints | Kernel | Chio |
Req 10.5 | Retention and archive | RetentionConfig | Chio and operator |
Req 10.7 | Fail-closed guards, SIEM export | Deny receipt | Chio and operator |
Req 11.5 | Checkpoint verification | Kernel | Chio |
Req 12.8 | Capability scope | CapabilityToken | Chio and operator |
Req 12.10 | Evidence export, revocation | Evidence package | Operator |
- Req 1.3, traffic restricted.
egress_allowlistlimits the targets an agent reaches. It acts at the application layer, beside the network ACLs the operator keeps. - Req 6.5, changes managed. The policy hash in every receipt ties an invocation to the policy version in force.
- Req 7.2 and 7.2.5, need to know and least privilege.
CapabilityToken.scopenarrows reachable tools,ToolGrant.constraintsnarrow parameters, and delegation only attenuates. An agent holds no implicit authority. - Req 7.3, access-control systems. Capabilities are issued through
chio-governanceandchio-control-planeand revoked throughrevocation_runtime. - Req 8.2 and 8.3, identification and authentication.
CapabilityToken.subjectidentifies each agent, andWorkloadIdentityrecords its normalized runtime identity. Each agent holds an Ed25519 keypair; DPoP binds every call to the subject throughaction_hashand a nonce, and refuses a proof that has outlivedproof_ttl_secs(default 300 seconds). - Req 8.6, account use. Capabilities expire at
expires_at, and revocation and delegation-chain validation end them before then. - Req 10.2 and 10.3, audit logs and their protection. Every mediated decision emits a signed receipt to an append-only store. The kernel signs a checkpoint over each
checkpoint_batch_sizereceipts (default 100), incrates/kernel/chio-kernel/src/checkpoint.rs, andbuild_inclusion_proofproduces the inclusion proofs. - Req 10.5, log history retained.
RetentionConfig.retention_days(default 90) andmax_size_bytesrotate the live store, and archival keeps the checkpoint rows. Set the retention period to PCI's one-year minimum. - Req 10.7, control failures detected. The fail-closed pipeline signs a deny receipt on error, and the SIEM adapter in
crates/observability/chio-siem/src/exporter.rsstreams the events. The operator owns alert escalation. - Req 11.5, unexpected changes detected. Merkle checkpoint verification detects tampering in the receipt log; network intrusion detection belongs to other controls.
- Req 12.8, service providers. Capability scope restricts which third-party tool servers an agent reaches. Auditing those providers is the operator's work.
- Req 12.10, incident response. Evidence packages support investigation, and revocation restricts future governed calls. The HITRUST readiness package includes an incident runbook the operator adapts, staffs, and tests.
Chio narrows the PCI scope of the agent layer by limiting what agents can call, and the tool servers that handle cardholder data keep their own PCI obligations. Requirements 5 and 9 fall outside a tool-governance layer, as does Requirement 1 apart from the egress control above. The implementation inventory is docs/compliance/pci-dss-v4.md; PCI SSC retired v4.0 on December 31, 2024, and the v4.0.1 standard and assessment documents replace it.
Four of the ten OWASP LLM risks are answered at the kernel's boundary
The OWASP Top 10 for LLM Applications (2025 edition) names the most critical security risks for LLM-based software. The risks that act on the world concentrate at the tool-invocation boundary, where the kernel decides each governed call.
| Risk | Chio control | Evidence record | Owner |
|---|---|---|---|
LLM01 Prompt Injection | Input and injection guards | GuardEvidence | Chio and operator |
LLM02 Sensitive Information Disclosure | Leak, sanitization, data guards | Query verdict | Chio |
LLM03 Supply Chain | Signed tool manifests | ToolManifest | Chio and operator |
LLM04 Data and Model Poisoning | Data-layer write guards | Query verdict | Operator |
LLM05 Improper Output Handling | Post-invocation guards, schemas | Query verdict | Chio |
LLM06 Excessive Agency | Capabilities, caps, approvals | Governed | Chio |
LLM07 System Prompt Leakage | Sanitization, capability scope | GuardEvidence | Chio and operator |
LLM08 Vector and Embedding Weaknesses | Vector-store guard, egress | GuardEvidence | Chio and operator |
LLM09 Misinformation | Signed receipts | ChioReceipt | Chio and operator |
LLM10 Unbounded Consumption | Budget caps, velocity guard | Financial | Chio |
- LLM01. Input-validation guards check tool-call arguments, and prompt-injection and jailbreak detectors run as application-layer guards. Every trigger lands in
ChioReceipt.evidenceas aGuardEvidenceentry. - LLM02.
secret_leak,response_sanitization,data_flow, and column-level constraints on the SQL and vector guards act on results;QueryResultGuardblocks or redacts them, and capability scope limits the reachable data sources. - LLM03. Tool manifests carry Ed25519 signatures that are checked before registration, the
patch_integrityguard checks patch content, and workload-identity attestation names the runtime. A manifest signature covers the tool definition, and the server binary sits outside it. - LLM04. Data-layer guards restrict what a deployed agent writes back into tool-reachable stores. Training-data poisoning sits outside the tool-governance layer, with the operator.
- LLM05.
response_sanitization, the post-invocationQueryResultGuard, and structured output schemas checked byrequest_matchingapply to output. A post-invocation block verdict keeps unsafe output from the agent and from any downstream tool. - LLM06. Capability tokens bound tool reach, typed constraints bound arguments, delegation chains only attenuate, and velocity and budget caps bound rate and spend.
GovernedAutonomyTierrequires step-up approval for sensitive tiers, DPoP attributes each call to its agent, and revocation contains it. Evaluation is per invocation, and the plan as a whole is the application's. - LLM07. Where system prompts flow through governed tools, response sanitization and secret-leak match known prompt content, and capability scope withholds introspection tools that would expose prompts.
- LLM08. The vector-store guard restricts the embeddings an agent reads or writes, the egress allowlist limits retrieval endpoints, and column constraints refuse sensitive fields before vectorization.
- LLM09. Receipts record what was returned and who received it, which supports correction workflows. Factuality evaluation belongs to the application.
- LLM10. Budget caps (
max_cost_per_invocation,max_total_cost) hold monetary spend atomically per invocation and per grant, the velocity guard caps invocation and spend rate, revocation is checked before each later governed call, and grant expiry bounds time.
The four are LLM02, LLM05, LLM06, and LLM10. Five have their root cause inside the model, so Chio complements the model-layer defenses there, and LLM04 belongs to the training pipeline. The guards live in crates/guards/chio-guards/src/ and crates/guards/chio-data-guards/src/.
Five frameworks have their own mapping pages
The repository maps PCI DSS v4.0.1 and the OWASP LLM Top 10 here, and the EU AI Act, NIST AI RMF, ISO/IEC 42001, Colorado SB 24-205, and HITRUST i1 on their own pages. Each criterion number on a mapping page is one its source document names.
Colorado replaced SB 24-205 with SB 26-189 in May 2026. The enacted act addresses covered automated decision-making technology, including documentation, retained records, consumer notices, and human review. A receipt records each governed operation for that review, and the operator documents applicability, consumer notices, and the human-review process. The Colorado page carries the declaration, retention, integrity, and accounting controls.
SOC 2 and the HIPAA Security Rule have no control matrix in the published mapping. Evaluate the applicable criteria with the assessment owner from Capabilities for scoped access and revocation, Receipts for the per-invocation record, and Guards for the named controls, and record the organizational evidence separately.
A governed run becomes a package an assessor verifies offline
The workflow starts from one kernel run, so every file it exports has a producer. Complete the Rust setup, install Chio and jq, then run the steps in order from the example project. The commands read with --admin-all because the receipt database is a fresh local one that belongs to this run.
Produce a bounded evidence run
Run two allowed tool calls and an out-of-scope denial through a kernel with SQLite receipts and a checkpoint for every receipt.
Complete the project setup, then run the program from federation-guide/. The download includes every constructor and input.
cargo run --locked --bin evidencetwo allowed calls; one out-of-scope denial; handler calls 2 three receipt signatures verified; checkpoint batch size 1 wrote evidence-run/receipts.sqlite3, window.json, and kernel-public-key.txt
The tool records a local result and counts handler invocations. The program saves the actual capture window and expected counts. This is a reproducible technical run, not evidence of a production assessment or a complete organizational control.
Read the complete program 36 lines · complete file
use chio_kernel::Verdict;
use federation_guide::*;
use serde_json::json;
use std::{path::Path, sync::atomic::Ordering};
#[tokio::main]
async fn main() -> Result<(), Error> {
let directory = Path::new("evidence-run");
let host = host(directory)?;
let since = now();
for id in ["review-a", "review-b"] {
let response = host
.kernel
.evaluate_tool_call(&request(&host.capability, id))
.await?;
assert_eq!(response.verdict, Verdict::Allow);
record(directory, id, &response)?;
}
let mut forbidden = request(&host.capability, "review-denied");
forbidden.tool_name = "delete".into();
let denied = host.kernel.evaluate_tool_call(&forbidden).await?;
assert_ne!(denied.verdict, Verdict::Allow);
record(directory, "denied", &denied)?;
assert_eq!(host.calls.load(Ordering::SeqCst), 2);
let until = now();
std::fs::write(
directory.join("window.json"),
serde_json::to_vec_pretty(
&json!({"since":since,"until":until,"boundary":"admin-all","capabilityId":host.capability.id,"expectedAllow":2,"expectedDeny":1}),
)?,
)?;
println!("two allowed calls; one out-of-scope denial; handler calls 2");
println!("three receipt signatures verified; checkpoint batch size 1");
println!("wrote evidence-run/receipts.sqlite3, window.json, and kernel-public-key.txt");
Ok(())
}Open the source file. The shared kernel host registers the tool, issues the capability, and persists receipts. Each program asserts its expected refusals; keys, timestamps, and digests change between runs.
Collect samples from the same window
EVIDENCE_SINCE=$(jq -r .since evidence-run/window.json)
EVIDENCE_UNTIL=$(jq -r .until evidence-run/window.json)
mkdir -p samples
chio receipt list --receipt-db evidence-run/receipts.sqlite3 --admin-all \
--since "$EVIDENCE_SINCE" --until "$EVIDENCE_UNTIL" \
--outcome allow --limit 100 > samples/allow.jsonl
chio receipt list --receipt-db evidence-run/receipts.sqlite3 --admin-all \
--since "$EVIDENCE_SINCE" --until "$EVIDENCE_UNTIL" \
--outcome deny --limit 100 > samples/deny.jsonl
jq -s length samples/allow.jsonl
jq -s length samples/deny.jsonl2 1
Sampling and export read the same saved window. A limit of 100 covers this three-receipt run; a larger assessment defines its sampling method and reconciles the population.
Export with complete checkpoint coverage
EVIDENCE_SINCE=$(jq -r .since evidence-run/window.json)
EVIDENCE_UNTIL=$(jq -r .until evidence-run/window.json)
chio evidence export --receipt-db evidence-run/receipts.sqlite3 --admin-all \
--since "$EVIDENCE_SINCE" --until "$EVIDENCE_UNTIL" \
--require-proofs --output evidence-package
chio evidence verify --input evidence-packageevidence package verified tool_receipts: 3 child_receipts: 0 checkpoints: 3 checkpoint_publications: 3 checkpoint_witnesses: 2 checkpoint_consistency_proofs: 2 checkpoint_equivocations: 0 capability_lineage: 1 inclusion_proofs: 3 uncheckpointed_receipts: 0 authorized_receipts: 2 trace_observations: 0 advisory_evaluations: 0 verified_files: 12 child_receipt_scope: FullQueryWindow transparency_preview_logs: 1 publication_state: transparency_preview
You should see three receipts, three inclusion proofs, three checkpoints, and zero uncheckpointed receipts. Compare those counts with evidence-run/window.json. The package carries receipt bytes and lineage, the query scope, checkpoint signatures, inclusion proofs, and a file manifest.
Refuse an export without a read boundary
chio evidence export --receipt-db evidence-run/receipts.sqlite3 --output missing-boundaryerror[CHIO-KERNEL-RECEIPT-READ-CONTEXT-MISSING]: evidence export needs a read boundary help: pass --tenant <id> to export one tenant's receipts, or --admin-all to export every tenant as the operator code: urn:chio:error:kernel:receipt-read-context-missing docs: https://chio.computer/docs/reference/errors#error-kernel-receipt-read-context-missing
Exit 1 is the expected refusal. A shell running with set -e stops at this command, so run it on its own.
Choose the authorized tenant or an explicit administrative read. A production query is never broadened to make this refusal pass.
Detect a changed package file
cp -R evidence-package altered-package
printf '\n' >> altered-package/receipts.ndjson
chio evidence verify --input altered-packageerror[CHIO-ATTEST-PROVENANCE-MISSING]: evidence package file hash mismatch for receipts.ndjson help: receipts.ndjson changed after the package was exported; verify the package as exported, or export it again code: urn:chio:error:attest:provenance-missing docs: https://chio.computer/docs/reference/errors#error-attest-provenance-missing
Exit 1 is the expected refusal. A shell running with set -e stops at this command, so run it on its own.
Keep the failed copy for investigation, obtain the original from the producer, and verify it again. A manifest regenerated around the changed files would erase the comparison.
The operator review completes the package
- Scope. Record the system, environment, tenant, review period, framework edition, and responsible reviewer.
- Signer. Compare the signer to an independently approved key. A self-consistent package leaves the choice of which organization to trust with the reviewer.
- Counts. Reconcile receipt counts against the expected workload and examine denials, missing checkpoints, and uncovered operations.
- Records. Attach the approved policy and its version, oversight decisions, retention schedule, and the organizational records each mapped requirement needs. In the example, the policy hash labels the host configuration rather than a compiled policy.
- Findings. Record findings, owners, deadlines, and acceptance decisions. Keep the package and the review record under the organization's access, backup, and retention controls.
Read the shared kernel host
The shared kernel host
The evidence, oversight, and revocation programs share this host. It creates a fresh key and receipt store, registers one local tool, issues a narrowly scoped capability, and checkpoints every receipt. The project download includes it.
use chio_core_types::{
capability::{
scope::{ChioScope, Operation, ToolGrant},
token::CapabilityToken,
},
Keypair,
};
use chio_kernel::*;
use serde_json::{json, Value};
use std::{
path::Path,
sync::{
atomic::{AtomicUsize, Ordering},
Arc,
},
time::{SystemTime, UNIX_EPOCH},
};
pub type Error = Box<dyn std::error::Error>;
pub fn now() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
}
struct ReviewTool {
calls: Arc<AtomicUsize>,
}
#[async_trait::async_trait]
impl ToolServerConnection for ReviewTool {
fn server_id(&self) -> &str {
"review"
}
fn tool_names(&self) -> Vec<String> {
vec!["record".into()]
}
fn tool_is_read_only(&self, _: &str) -> bool {
false
}
async fn invoke(
&self,
name: &str,
args: Value,
_: Option<&mut dyn NestedFlowBridge>,
) -> Result<Value, KernelError> {
if name != "record" {
return Err(KernelError::ToolServerError("unknown tool".into()));
}
self.calls.fetch_add(1, Ordering::SeqCst);
Ok(json!({"recorded":args}))
}
}
pub struct Host {
pub kernel: ChioKernel,
pub capability: CapabilityToken,
pub calls: Arc<AtomicUsize>,
pub key: Keypair,
}
pub fn host(directory: &Path) -> Result<Host, Error> {
host_with_retention(directory, None)
}
pub fn host_with_retention(
directory: &Path,
retention_config: Option<RetentionConfig>,
) -> Result<Host, Error> {
std::fs::create_dir(directory)?;
let kernel_key = Keypair::generate();
let mut kernel = ChioKernel::new(KernelConfig {
keypair: kernel_key.clone(),
ca_public_keys: Vec::new(),
max_delegation_depth: 3,
policy_hash: chio_core_types::sha256_hex(b"federation-review-policy-v1"),
allow_sampling: false,
allow_sampling_tool_use: false,
allow_elicitation: false,
max_stream_duration_secs: DEFAULT_MAX_STREAM_DURATION_SECS,
max_stream_total_bytes: DEFAULT_MAX_STREAM_TOTAL_BYTES,
require_web3_evidence: false,
// Keys and budget counters live for one process. A SQLite store
// retains parent capabilities and receipts for this run.
allow_ephemeral_receipt_log: true,
allow_ephemeral_revocation_store: true,
checkpoint_batch_size: 1,
retention_config,
memory_budget: chio_kernel::MemoryBudgetConfig::defaults(),
deadlines: chio_kernel::HotPathDeadlineConfig::default(),
});
kernel.set_receipt_store(Box::new(chio_store_sqlite::SqliteReceiptStore::open(
directory.join("receipts.sqlite3"),
)?))?;
let calls = Arc::new(AtomicUsize::new(0));
kernel.register_tool_server(Box::new(ReviewTool {
calls: calls.clone(),
}));
let subject = Keypair::generate();
let capability = kernel.issue_capability(
&subject.public_key(),
ChioScope {
grants: vec![ToolGrant {
server_id: "review".into(),
tool_name: "record".into(),
operations: vec![Operation::Invoke],
constraints: vec![],
max_invocations: Some(20),
max_cost_per_invocation: None,
max_total_cost: None,
dpop_required: None,
}],
..ChioScope::default()
},
600,
)?;
kernel.set_capability_trust_root(
kernel_key.public_key(),
chio_core_types::capability::attenuation::scope_hash(&capability.scope)?,
);
std::fs::write(
directory.join("kernel-public-key.txt"),
kernel_key.public_key().to_hex(),
)?;
std::fs::write(
directory.join("capability.json"),
serde_json::to_vec_pretty(&capability)?,
)?;
Ok(Host {
kernel,
capability,
calls,
key: kernel_key,
})
}
pub fn request(cap: &CapabilityToken, id: &str) -> ToolCallRequest {
ToolCallRequest {
request_id: id.into(),
capability: cap.clone(),
tool_name: "record".into(),
server_id: "review".into(),
agent_id: cap.subject.to_hex(),
arguments: json!({"document":"proposal-7","decision":"release"}),
dpop_proof: None,
execution_nonce: None,
governed_intent: None,
approval_token: None,
approval_tokens: vec![],
threshold_approval_proposal: None,
supplemental_authorization: None,
model_metadata: None,
federated_origin_kernel_id: None,
}
}
pub fn record(directory: &Path, name: &str, response: &ToolCallResponse) -> Result<(), Error> {
assert!(response.receipt.verify_signature()?);
std::fs::write(
directory.join(format!("{name}-receipt.json")),
serde_json::to_vec_pretty(&response.receipt)?,
)?;
Ok(())
}One bundle serves every framework. Two auditors running different examinations read the same signed records against different control checklists, and each first runs the signature, checkpoint, and signer checks in verify security evidence.
Verification names any exported file that changed
chio evidence export reads the local receipt database through the global --receipt-db flag and writes a bundle an auditor verifies offline. A local export names its scope with --tenant or --admin-all, and refuses when given neither.
$ chio --receipt-db ./receipts.db evidence export \
--policy-file ./policy.yaml --admin-all --output ./evidence-package
$ find ./evidence-package -type f | sort./evidence-package/README.txt ./evidence-package/capability-lineage.ndjson ./evidence-package/checkpoint-consistency-proofs.ndjson ./evidence-package/checkpoint-equivocations.ndjson ./evidence-package/checkpoint-publications.ndjson ./evidence-package/checkpoint-witnesses.ndjson ./evidence-package/checkpoints.ndjson ./evidence-package/child-receipts.ndjson ./evidence-package/inclusion-proofs.ndjson ./evidence-package/manifest.json ./evidence-package/policy/metadata.json ./evidence-package/policy/source.yaml ./evidence-package/query.json ./evidence-package/receipts.ndjson ./evidence-package/retention.json
The four checkpoint- files carry the transparency record for the window's checkpoints: publications, witness signatures, consistency proofs, and any recorded equivocation. The policy/ directory appears when --policy-file is supplied, and federation-policy.json joins it when --federation-policy constrains the export scope by a signed bilateral federation policy.
- Window.
--sinceand--until, both Unix seconds, narrow the receipts selected. - Coverage.
--require-proofsfails the export when any selected receipt lacks checkpoint coverage. - Manifest. The manifest records a SHA-256 digest and a byte count for every file the export wrote, so verification re-derives each file. One byte appended to
receipts.ndjsonfails with the file named, and the auditor knows which record to request again. - Fresh directory. The export refuses to write into a directory that already holds files.
A package that verifies shows the auditor three things. Each receipt was signed by the kernel key it names: the signature over its canonical body verifies against kernel_key, and action.parameter_hash recomputes from the parameters it carries. The checkpoint chain holds: signed Merkle roots cover the included batches and the inclusion proofs reproduce. Every manifest file still hashes to its recorded digest, and the manifest counts agree with the exported data.
When a policy is attached, the verifier also confirms that policy/metadata.json matches the manifest and that the source file it names is present. Comparing that source's hash with each receipt's policy_hash is the reviewer's step; the verifier leaves the policy source unhashed.
The operator owns the scope, the assessment, and the controls around the kernel
These frameworks apply to organizations, and Chio is infrastructure inside one. The mappings support the operator's self-assessment and follow the documents under docs/compliance/ in the Chio repository; organization-wide coverage is the operator's to establish.
- Scope. Determine the assessment scope, validate each deployed control, and retain the procedural and assessment evidence each row needs. Chio is an input to PCI scoping, and the operator draws the conclusion.
- Surrounding controls. Keep network-layer controls, PAN masking, encryption at rest, physical security, workforce training, and legal review. The Report on Compliance is the organization's.
- Operations. Escalate alerts from the SIEM stream, audit third-party providers, and adapt, staff, and test the incident response process.
- Model layer. Defend the training pipeline and evaluate factuality.
- Translation. Turn the evidence into each framework's language. Chio emits records and computes no cross-framework risk score.