AI Agent Audit Trails: SOC2 and GDPR
Map Veto's audit trail to specific SOC 2 controls (CC6.1, CC6.3, CC7.2, CC7.3, CC8.1) and GDPR articles (Art. 13-15, Art. 22, Art. 30). Complete audit record anatomy, retention policies, and tamper-evident logging.
Your SOC 2 auditor asks: "Show me every action your AI agent took on customer data last quarter." Your GDPR data subject asks: "Explain the automated decision that denied my loan application." Your CISO asks: "Which agent accessed production credentials at 2 AM on Tuesday?" If you cannot answer these questions in minutes with complete, tamper-evident records, you have an audit gap. And audit gaps become regulatory findings, fines, and front-page incidents.
What SOC 2 Requires
SOC 2 is built on five Trust Services Criteria: Security, Availability, Processing Integrity, Confidentiality, and Privacy. For AI agent audit trails, five specific Common Criteria controls are relevant:
- CC6.1 — Logical and Physical Access Controls — Requires deploying identity and access management controls including unique user IDs, multi-factor authentication for administrative functions, and role-based access control. For AI agents, this means every tool call must be traceable to a specific user session, agent identity, and authorization policy.
- CC6.2 — User Account Management — Requires secure creation, management, and deletion of accounts before, during, and after data access. For agents, this maps to lifecycle tracking: when an agent was created, what credentials it holds, and what happens when those credentials are revoked.
- CC6.3 — Access Authorization and Revocation — Requires managing data access based on users' responsibilities with least privilege and segmentation. This directly applies to per-tool, per-tenant agent policies. Your auditor wants to see: what was the agent authorized to do, and was that authorization appropriate for the task?
- CC7.2 — Monitoring System Components — Requires implementing infrastructure monitoring for all in-scope systems. For agents, this means continuous logging of every tool call, decision outcome, and execution result. Not just errors. Everything.
- CC7.3 — Security Event Analysis — Requires analyzing all identified security events to determine and prevent compromises. Your AI agent's denied tool calls, anomalous access patterns, and approval timeout events are all security events that must be aggregated, analyzed, and retained.
What GDPR Requires
GDPR Article 22 grants EU data subjects the right not to be subject to decisions "based solely on automated processing" that produce legal effects. Articles 13-15 require providing "meaningful information about the logic involved, as well as the significance and the envisaged consequences of such processing."
For AI agents, this means:
- Decision explainability — Every automated decision must be traceable to the policy that governed it, the data that informed it, and the logic that produced it.
- Human intervention pathway — Data subjects must be able to request human review of automated decisions. Your system must record when human review was requested, who reviewed it, and what the outcome was.
- Data subject access — When a data subject requests their data under Article 15, you must be able to produce every decision your agent made about them, with full context.
The Anatomy of a Complete Audit Record
A compliant audit record is not just "tool X was called at time Y." It must capture the full decision chain: who triggered the action, what the agent was trying to do, what policy governed the decision, what the outcome was, and (if applicable) who reviewed it.
{
"record_id": "aud_7f8g9h0i1j2k",
"timestamp": "2026-04-04T09:15:33.721Z",
"event_type": "tool_call_decision",
"identity": {
"agent_id": "agent_customer_ops_v3",
"session_id": "sess_abc123def456",
"triggered_by": {
"user_id": "user_789",
"email": "j.smith@acmecorp.com",
"role": "support_l2",
"ip_address": "198.51.100.42"
},
"tenant_id": "tenant_acme",
"organization_id": "org_acme_corp"
},
"tool_call": {
"tool": "query_customer_data",
"arguments": {
"customer_id": "cust_456",
"fields": ["name", "email", "order_history"],
"date_range": "last_90_days"
},
"argument_hash": "sha256:a1b2c3d4..."
},
"policy_evaluation": {
"policy_name": "acme-support-agent-v2.1",
"policy_version": "2.1",
"rule_matched": "rule_3_customer_data_access",
"conditions_evaluated": [
{"condition": "role == support_l2", "result": true},
{"condition": "fields subset of allowed_fields", "result": true},
{"condition": "customer belongs to tenant", "result": true}
],
"decision": "allow",
"reason": "All conditions satisfied for L2 support data access"
},
"execution": {
"started_at": "2026-04-04T09:15:33.891Z",
"completed_at": "2026-04-04T09:15:34.203Z",
"duration_ms": 312,
"success": true,
"result_hash": "sha256:e5f6g7h8..."
},
"compliance_metadata": {
"gdpr_relevant": true,
"data_subject_id": "cust_456",
"legal_basis": "legitimate_interest",
"retention_policy": "3years",
"exportable": true
}
}Mapping Veto to SOC 2 Controls
Here is how Veto's audit trail maps to each relevant SOC 2 control, with the specific evidence your auditor expects:
┌──────────┬─────────────────────────────┬──────────────────────────────────────┐ │ Control │ Requirement │ Veto Evidence │ ├──────────┼─────────────────────────────┼──────────────────────────────────────┤ │ CC6.1 │ Identity + access mgmt │ Every decision log includes: │ │ │ │ user_id, agent_id, role, tenant_id, │ │ │ │ session_id, IP address. │ │ │ │ Export: /api/v1/logs?filter=identity │ ├──────────┼─────────────────────────────┼──────────────────────────────────────┤ │ CC6.2 │ Account lifecycle │ Agent creation/revocation events │ │ │ │ logged. API key rotation tracked. │ │ │ │ Export: /api/v1/logs?filter=lifecycle│ ├──────────┼─────────────────────────────┼──────────────────────────────────────┤ │ CC6.3 │ Least privilege / RBAC │ Policy definitions (YAML) show │ │ │ │ per-role, per-tool authorization. │ │ │ │ Denial logs prove enforcement. │ │ │ │ Export: /api/v1/policies + /logs │ ├──────────┼─────────────────────────────┼──────────────────────────────────────┤ │ CC7.2 │ Continuous monitoring │ Every protect() call logged. │ │ │ │ Real-time dashboard shows volume, │ │ │ │ denial rate, approval queue depth. │ │ │ │ Export: /api/v1/logs (full stream) │ ├──────────┼─────────────────────────────┼──────────────────────────────────────┤ │ CC7.3 │ Security event analysis │ Denied calls, anomalies, timeout │ │ │ │ events flagged and aggregated. │ │ │ │ Alert rules configurable per tool. │ │ │ │ Export: /api/v1/logs?filter=security │ ├──────────┼─────────────────────────────┼──────────────────────────────────────┤ │ CC8.1 │ Change authorization │ Policy version history tracked. │ │ │ │ Every policy change logged with │ │ │ │ author, diff, and effective date. │ │ │ │ Export: /api/v1/policies/history │ └──────────┴─────────────────────────────┴──────────────────────────────────────┘
Mapping Veto to GDPR Requirements
┌─────────────────┬──────────────────────────────┬──────────────────────────────┐ │ GDPR Article │ Requirement │ Veto Evidence │ ├─────────────────┼──────────────────────────────┼──────────────────────────────┤ │ Art. 13-15 │ Meaningful info about logic │ policy_evaluation block in │ │ (Right to info) │ involved in automated │ each log entry shows: rule │ │ │ decision-making │ matched, conditions, reason. │ ├─────────────────┼──────────────────────────────┼──────────────────────────────┤ │ Art. 22(1) │ Right not to be subject to │ require_approval action │ │ (Automated │ solely automated decisions │ ensures human involvement. │ │ decisions) │ with legal effects │ Approval logs prove it. │ ├─────────────────┼──────────────────────────────┼──────────────────────────────┤ │ Art. 22(3) │ Right to human intervention, │ Approval workflow with │ │ (Safeguards) │ express point of view, │ reviewer identity, decision, │ │ │ contest decision │ and reasoning recorded. │ ├─────────────────┼──────────────────────────────┼──────────────────────────────┤ │ Art. 15(1)(h) │ Data subject access to │ Per-subject log export: │ │ (Access right) │ automated decision info │ /api/v1/logs?subject_id=X │ │ │ │ returns all decisions about │ │ │ │ that individual. │ ├─────────────────┼──────────────────────────────┼──────────────────────────────┤ │ Art. 17 │ Right to erasure │ Audit logs are retained for │ │ (Right to be │ │ compliance but subject data │ │ forgotten) │ │ can be anonymized on request. │ ├─────────────────┼──────────────────────────────┼──────────────────────────────┤ │ Art. 30 │ Records of processing │ Full log export satisfies │ │ (Processing │ activities │ processing activity records │ │ records) │ │ for agent-based processing. │ └─────────────────┴──────────────────────────────┴──────────────────────────────┘
Implementation: Structured Logging with Veto
Veto generates audit records automatically on every protect() call. You do not need to build a separate logging pipeline. But you can also forward Veto's logs to your existing SIEM for centralized analysis:
from veto import Veto
import structlog
from datetime import datetime, timedelta
veto = Veto(api_key="veto_live_xxx", project="production-agent")
logger = structlog.get_logger()
# Forward every decision to your logging infrastructure
@veto.on_decision
def forward_to_siem(decision):
logger.info(
"agent_decision",
record_id=decision.id,
tool=decision.tool,
action=decision.action,
reason=decision.reason,
user_id=decision.context.get("user_id"),
tenant_id=decision.context.get("tenant_id"),
agent_id=decision.context.get("agent_id"),
policy_name=decision.policy.name,
policy_version=decision.policy.version,
rule_matched=decision.policy.rule_index,
timestamp=decision.timestamp.isoformat(),
duration_ms=decision.duration_ms,
)
# Query logs for SOC 2 auditor: all denied actions, last quarter
def generate_soc2_denial_report(quarter_start: datetime):
quarter_end = quarter_start + timedelta(days=90)
denied = veto.logs.query(
action="deny",
since=quarter_start,
until=quarter_end,
format="csv",
)
return denied
# Query logs for GDPR data subject access request
def handle_dsar(subject_id: str):
"""Article 15: produce all decisions made about this individual."""
records = veto.logs.query(
subject_id=subject_id,
include_policy_details=True,
include_execution_results=True,
format="json",
)
return records
# Query logs for incident investigation
def investigate_incident(start: datetime, end: datetime, agent_id: str):
"""CC7.3: analyze security events for a specific agent."""
events = veto.logs.query(
agent_id=agent_id,
since=start,
until=end,
include_session_context=True,
)
anomalies = [e for e in events if e.get("anomaly_score", 0) > 0.8]
denials = [e for e in events if e["action"] == "deny"]
return {
"total_events": len(events),
"anomalies": anomalies,
"denials": denials,
}Retention Policies
Different frameworks require different retention periods. Veto lets you configure retention per log category:
retention:
# SOC 2: retain for audit window + buffer
decisions:
duration: 3years
reason: "SOC 2 CC7.2 — monitoring records"
# GDPR: retain until no longer necessary for processing purpose
# but keep anonymized records for compliance evidence
gdpr_relevant:
duration: 6years
anonymize_after: 3years
reason: "GDPR Art. 5(1)(e) — storage limitation"
# Financial: SOX/PCI require extended retention
financial_decisions:
duration: 7years
reason: "SOX Section 802 — record retention"
# Security events: retain for investigation capability
security_events:
duration: 1year
reason: "CC7.3 — security event analysis"
# Policy change history: retain indefinitely
policy_changes:
duration: indefinite
reason: "CC8.1 — change management evidence"
export:
format: jsonl
encryption: aes-256-gcm
destinations:
- type: s3
bucket: "audit-logs-production"
prefix: "veto/"
- type: siem
endpoint: "https://siem.internal/api/v1/ingest"
api_key_env: "SIEM_API_KEY"Log Integrity: Tamper Evidence
An audit log that can be modified after the fact is worthless. Auditors need assurance that logs have not been tampered with. Veto's logs are append-only and include content hashes that chain each record to the previous one. If any record is modified or deleted, the hash chain breaks and the tampering is detectable.
For additional assurance, export logs to an immutable store (S3 with Object Lock, Azure Immutable Blob Storage, or a dedicated write-once archive). Veto's export pipeline supports scheduled exports to any of these destinations.
The EU AI Act Overlay
If your agent is classified as high-risk under the EU AI Act (see our EU AI Act guide), Article 12 requires "automatic recording of events (logs) over the lifetime of the system." Article 26(6) requires deployers to retain these logs for "a period of at least six months." Veto's default retention of 1 year exceeds this minimum, and the configurable retention policies let you align with your specific regulatory requirements.
What Your Auditor Actually Asks For
After working with teams through SOC 2 audits, here are the five questions auditors consistently ask about AI agent systems, and the evidence Veto provides:
- "What access controls exist for the AI system?" — Policy YAML files showing per-tool, per-role authorization rules. Denial logs proving enforcement.
- "How do you monitor the AI system's behavior?" — Real-time dashboard showing decision volume, denial rates, and approval queue depth. Alert configuration for anomalous patterns.
- "Can you show me a specific decision chain?" — Full decision record with identity, tool call, policy evaluation, execution result, and (if applicable) human approval. Queryable by session, user, agent, or time range.
- "How are changes to the AI system authorized?" — Policy version history with author, diff, and effective date. Every policy change is itself an auditable event.
- "What is your log retention and integrity assurance?" — Configurable retention per category. Hash-chained records. Export to immutable storage. Encryption at rest and in transit.
Getting Started
Veto generates audit records automatically. There is no separate logging SDK to integrate, no pipeline to build, no schema to maintain. Every protect() call produces a complete audit record. Configure retention and export in the dashboard, and your audit trail is production-ready.
Start free and get audit-ready today, or read about human-in-the-loop patterns for the approval workflows that satisfy GDPR Article 22.
Related posts
Build your first policy