Skip to contentNew: Does ChatGPT recommend your brand? Free 60-second AI visibility check →
Research summary — verify scope with your SOC 2 auditor before standardizing

Audit Trail for LLM Prompts (SOC 2, 2026)

By DDH Research Team at Digital Dashboard HubUpdated

Stop writing AI prompts from scratch.

Tell us your business + your task + your model. We write the prompt — perfectly tuned for ChatGPT, Claude, Grok, Gemini, Midjourney, or any model. Plus 500+ pre-built prompts in your library.

14 days, no card. Cancel in 2 clicks.

SOC 2's Trust Services Criteria don't name LLMs explicitly, but auditors in 2026 map LLM-specific risks to existing criteria: CC6 (Logical and Physical Access Controls), CC7 (System Operations including monitoring of system operations), CC8 (Change Management), and Confidentiality / Processing Integrity / Privacy as scoped. Every modern SOC 2 audit of an AI SaaS includes a section on AI-specific evidence — and the foundation of that section is the audit trail for LLM invocations.

This guide ships a production-grade audit trail design: the log schema (what to record), the storage choice (CloudWatch / Cloud Logging / Datadog / Elastic), the retention policy (how long), the encryption posture (KMS / Key Vault), the access controls (who can read, who can query, who can delete), and the query patterns auditors and DSR handlers actually use. Plus code patterns in Python and TypeScript that you can drop into your application.

The audit trail is also load-bearing for HIPAA (Security Rule audit controls under 45 CFR 164.312(b)) and GDPR (accountability under Article 5(2), data subject access requests under Article 15). The same log can serve all three regulatory layers if designed correctly.

Related: /calc/soc2-prep-cost-for-ai-startups · /tutorial/implement-dlp-for-llm-apps · /calc/hipaa-ai-deployment-cost-2026.

Digital Dashboard Hub

Following along is one thing; saving the prompt so you can run it tomorrow is another. DDH's AI Prompt Builder + Saved Prompt Library is where the patterns above live, version, and re-export to any model.

Start free 14-day trial — AICHAT30 = 30% off Pro for 3 months.

LLM audit log schema — fields and rationale

Feature
Field
Type
Why auditors ask
request_id (UUID)stringCorrelation key across application logs, LLM vendor billing, downstream events
timestamp (RFC 3339 with timezone)stringOrdering, time-bounded queries, retention-aging
user_id (internal identifier)stringPer-user export for DSR; user behavior analytics during incidents
session_idstringGroup multi-turn conversations; correlate with session-level events
tenant_id / organization_idstringPer-tenant data isolation evidence; per-customer DSR
vendor (openai / anthropic / azure-openai / bedrock / vertex)enumVendor due diligence evidence; per-vendor incident response routing
model (specific model ID)stringPer-model risk classification; per-model billing reconciliation
endpoint (chat / responses / embeddings / etc)enumEndpoint scope verification against BAA / ZDR-eligible lists
purpose_code (business purpose / use case)enumMinimum-necessary evidence; per-use-case lawful basis
data_classification (public / internal / confidential / restricted-PHI / restricted-PII)enumConfidentiality scope evidence; access control gating
input_token_countintVolume reconciliation against vendor billing; capacity planning
output_token_countintSame
dlp_detected_entity_types (list, types only)string[]DLP coverage evidence; minimum-necessary documentation
dlp_action_taken (none / redact / replace / tokenize / refused)enumSame
latency_msintSLA monitoring; vendor performance
status (success / error / refused-by-policy / refused-by-dlp)enumError rate monitoring; refusal pattern analysis
error_code (if error)stringVendor failure pattern analysis
trace_id (W3C / OpenTelemetry)stringCorrelation with full distributed trace

Sources fetched June 2026: AICPA Trust Services Criteria (CC6-CC8 access, system operations, change management), 45 CFR 164.312(b) HIPAA Security Rule audit controls, NIST SP 800-92 (Guide to Computer Security Log Management). Schema is a synthesis of fields commonly required across SOC 2 + HIPAA + GDPR audits for AI SaaS in 2026. Adapt to your specific control environment.

What auditors actually look at

SOC 2 Type 2 auditors sample log entries during the audit. They will pick a small set of dates / users / events and ask you to produce the audit log for the corresponding time window. The audit log must contain (1) sufficient detail to reconstruct the event, (2) timestamp accuracy (synchronized clock — NTP-backed), (3) immutability evidence (the log entry cannot be edited or deleted post-hoc by application users), (4) access controls (only authorized roles can read the log; access is itself audited).

Common findings: (a) log entries missing key fields — auditor asks 'how do you know what data classification was processed?' and the answer is 'we don't log that'. Mitigation: include data_classification + purpose_code in every entry. (b) Logs editable / deletable by application users — auditor flags as access control gap. Mitigation: write-only access for the application user; admin / SRE roles can read but not edit existing entries; deletion only via lifecycle policy. (c) Insufficient retention — auditor asks for entries from the start of the observation window and you don't have them. Mitigation: retention longer than the observation window plus buffer.

AI-specific findings in 2026 audits: (a) no record of which model was used — auditor asks 'how do you know GPT-5 was used vs GPT-3.5?' for the sampled event. Mitigation: log the specific model ID. (b) No DLP evidence — auditor asks 'how do you know minimum-necessary was applied?' Mitigation: log dlp_detected_entity_types + dlp_action_taken. (c) Vendor / endpoint mismatch — auditor asks 'this entry says Bedrock but the BAA scope is Azure OpenAI — explain'. Mitigation: vendor inventory must match what the logs show.

Pro tip: provide the auditor with a 5-10 row sample of the audit log early in the audit. They will tell you what additional fields they want to see, and you can extend the schema before the formal observation starts.


Storage choice tree

AWS-native production: CloudWatch Logs in the same region as the application. Pros: integrated with AWS IAM, KMS encryption, native retention policies, queryable via CloudWatch Logs Insights, can subscribe to events for real-time alerting. Cons: query language is bounded; high-volume queries can be slow.

AWS with heavy querying needs: ship logs from CloudWatch to S3 (Athena queryable) or to Datadog / Elastic. Pros: rich query language, dashboards. Cons: additional cost, additional storage to secure.

GCP-native: Cloud Logging with a dedicated log bucket. Same pros/cons as CloudWatch.

Azure-native: Azure Monitor Logs with a dedicated Log Analytics Workspace. Same pros/cons.

Datadog / Elastic / Splunk: appropriate for shops already on these platforms. Pros: cross-cloud, rich query, mature integrations. Cons: additional vendor relationship and DPA review.

Multi-cloud: ship audit logs to a centralized SIEM (Splunk / Sumo / Elastic / Datadog) with normalized schema. Pros: unified view across clouds. Cons: more moving parts; ensure SIEM is in scope on SOC 2 too.

Common mistake: writing to two destinations without a single source of truth. Pick one canonical store and (optionally) replicate read-only for analytics. The canonical store is what the auditor samples from.


Retention policy math

Retention drives storage cost and compliance posture. Set retention deliberately, not by default.

SOC 2 Type 2: audit observation periods are typically 6-12 months. Auditor will sample the entire observation period. Retain at least 12 months for the SOC 2 layer.

HIPAA: documentation retention is 6 years from the date of creation or last in effect (45 CFR 164.530(j)). For audit logs, the safe interpretation is 6 years. Some Covered Entities retain 7-10 years to align with state record retention requirements.

GDPR: no specific retention period; the principle is retain for as long as necessary for the purpose. Audit logs are typically retained as long as the underlying processing purpose plus a reasonable evidentiary window — commonly 3-6 years.

PCI-DSS (if in scope, rare for LLM apps): logs retained at least 1 year with 3 months readily available (PCI-DSS 10.7).

Practical guidance: pick the longest required retention across all applicable frameworks. For most AI SaaS handling US healthcare + GDPR + SOC 2, 7 years is the safe floor. Adjust as your framework mix changes.

Storage cost math at 7 years: 1 audit log entry ~1-3 KB. 1M calls/month × 12 months × 7 years = 84M entries × 2 KB avg = 168 GB. At CloudWatch storage cost (~$0.03/GB/month after the first ingest charge) = ~$5/month at 168 GB stored. Negligible for most production workloads. The bigger cost is ingest ($0.50/GB ingested = $1 to ingest 2 GB of logs per month at 1M calls).


Access controls and the immutability gap

Audit logs must be immutable from the perspective of application code. Once written, an entry cannot be modified or deleted by the same application that wrote it. Implementation patterns:

Pattern 1: write-only IAM. The application's IAM role has logs:PutLogEvents but not logs:DeleteLogStream or logs:DeleteLogGroup. Operator roles (Security, SRE) have read but not delete. Only a designated audit-management role (limited members, MFA-required, just-in-time access) can prune.

Pattern 2: dedicated audit account. Ship logs cross-account from the production account into a dedicated audit AWS / GCP / Azure account. The production account cannot delete logs in the audit account. This is the gold standard for SOC 2 and HIPAA.

Pattern 3: immutable storage. S3 Object Lock in Compliance mode prevents deletion of objects for the retention period — even by root account. For the strongest evidence of immutability, ship a daily compressed log file to an Object-Locked S3 bucket.

Pattern 4: cryptographic chain. Each log entry includes a hash of the previous entry, forming an append-only Merkle chain. Tampering requires regenerating the chain, which is detectable. This is overkill for most workloads but useful for high-stakes integrity requirements (financial, medical device).

Access auditing: who reads the audit log is itself an auditable event. Enable CloudTrail / Cloud Audit Logs / Azure activity logs on the audit log store and review access patterns periodically.


Per-user export for DSR / patient access requests

GDPR Article 15 (right of access) and HIPAA's right of access (45 CFR 164.524) require the controller / Covered Entity to provide an accounting of disclosures and (under GDPR specifically) the personal data processed. For an AI SaaS, the audit log is the canonical record of LLM-based processing involving the data subject.

Build a DSR export endpoint: GET /api/dsr/export/<user_id>?from=<date>&to=<date>. Authenticate the caller (typically support staff with elevated permissions, or the user themselves via authenticated portal). Query the audit log for entries matching user_id. Return as JSON or CSV with all the schema fields populated.

What NOT to include: the prompt content / response content if you don't retain them (per ZDR posture). If you do retain prompt/response content (separately, in a customer-controlled store), DSR export includes that separately under appropriate access controls.

DSR deletion (right to be forgotten under GDPR Article 17): deletion of audit log entries is generally NOT permitted because the entries are evidence of regulatory compliance. The Article 17 exception (e) — 'for compliance with a legal obligation' — typically applies. Document this in your DSR process and explain to the data subject that audit log entries are retained as compliance evidence.

Anonymization on deletion: when a user account is deleted, you may anonymize the user_id in the audit log (replace with a one-way hash) to preserve aggregate analytics without retaining the link to the individual. This satisfies the spirit of erasure while preserving compliance evidence. Document the approach.


Common implementation gaps

Gap 1: relying on the LLM vendor's billing data as the audit trail. Vendor billing data is high-level (per-day usage, per-model totals) — not sufficient for SOC 2 sampling. Build your own audit trail in your application.

Gap 2: synchronous audit log writes that block on log store availability. If CloudWatch is briefly unavailable, your application stalls. Mitigation: write to a local durable queue first, drain to log store asynchronously.

Gap 3: logging the prompt content in the audit log. The audit log becomes a second PHI / sensitive store that must be safeguarded equivalently. Mitigation: log metadata only (token counts, DLP entity types, purpose codes); store prompt content separately under tighter access controls if retained at all.

Gap 4: not logging refused calls. If DLP refuses a call, the refusal is an auditable event. Log it.

Gap 5: not logging error calls. If the vendor returns 5xx, the failed call is an auditable event. Log it with error_code.

Gap 6: misaligned clocks. NTP-sync every host. Log entries with skewed clocks are unreliable evidence.

Gap 7: failing to test the audit trail. Periodically run synthetic test calls and verify the corresponding log entries appear in the canonical store with the expected schema.

Step-by-step — implement the audit trail in TypeScript

  1. 1

    Define the audit log type

    Create src/lib/audit/llm-audit-log.ts: export interface LlmAuditLogEntry { request_id: string; timestamp: string; user_id: string; session_id?: string; tenant_id: string; vendor: 'openai' | 'anthropic' | 'azure-openai' | 'bedrock' | 'vertex'; model: string; endpoint: 'chat' | 'responses' | 'embeddings' | 'batch'; purpose_code: string; data_classification: 'public' | 'internal' | 'confidential' | 'restricted-phi' | 'restricted-pii'; input_token_count: number; output_token_count: number; dlp_detected_entity_types: string[]; dlp_action_taken: 'none' | 'redact' | 'replace' | 'tokenize' | 'refused'; latency_ms: number; status: 'success' | 'error' | 'refused-by-policy' | 'refused-by-dlp'; error_code?: string; trace_id?: string; }. This is the canonical shape. Every LLM call writes one entry.

  2. 2

    Build a single wrapper around every LLM client

    Create src/lib/llm/safe-llm-client.ts that wraps the OpenAI / Anthropic / Bedrock SDKs. Every call goes through this wrapper. The wrapper: (1) accepts the prompt + metadata (user_id, tenant_id, purpose_code, data_classification); (2) calls DLP if data_classification is restricted-*; (3) invokes the LLM; (4) measures latency; (5) writes the audit log entry; (6) returns the response. Pattern: export async function safeLlmCall<T>(opts: SafeLlmCallOpts<T>): Promise<T> { const start = Date.now(); const requestId = crypto.randomUUID(); const deidentified = await dlp(opts.prompt, opts.data_classification); try { const response = await opts.vendor.invoke(deidentified.prompt); writeAuditLog({...}); return response; } catch (err) { writeAuditLog({...status: 'error', error_code: err.code}); throw err; } }.

  3. 3

    Pick storage — CloudWatch Logs / Cloud Logging / Datadog

    For AWS-native shops: CloudWatch Logs in the same region as your application. Create a dedicated Log Group (e.g., '/llm-audit/prod'), encrypt with a customer-managed KMS key, set retention to your required period (commonly 7 years for HIPAA, 6 years for SOX, 3 years for general SOC 2 Type 2 evidence retention). For GCP: Cloud Logging with a dedicated log bucket, encrypted with CMEK, with appropriate retention. For Azure: Azure Monitor Logs in a dedicated workspace, encrypted with customer-managed keys. For datadog / elastic / splunk shops: dedicated index with retention policy + encryption. Whichever you pick, encrypt at rest with a customer-managed key and lock access controls.

  4. 4

    Implement the write path with delivery guarantees

    Audit log writes must not lose entries. Synchronous writes in the request path add latency; asynchronous writes can lose entries if the buffer is lost on crash. Production pattern: write to a small in-process buffer + flush every N entries or M milliseconds + on process shutdown. For higher guarantee: write to a durable queue (SQS / PubSub / Service Bus) and have a separate worker drain to the log store. The queue acks confirm durability. Failure mode handling: if the audit log write fails, the calling code MUST handle the failure — typically by failing the user-facing request (fail-closed) for high-data-classification calls and logging the failure to a separate alerting channel.

  5. 5

    Build query patterns for auditor / DSR access

    Auditors and DSR handlers query the audit log frequently. Three canonical query patterns: (1) per-user export — 'all LLM calls for user_id=X in date range Y'. Index by user_id + timestamp. (2) per-incident — 'all LLM calls during incident window' filtered by vendor/model/error_code. Index by timestamp + status. (3) per-vendor reconciliation — aggregate token counts per vendor per day for billing reconciliation. CloudWatch Logs Insights, Cloud Logging analytics, or your APM's query language are all sufficient. Build the queries as saved searches in the platform and document them in the runbook so the DSR handler can run them on demand.

Use the data programmatically

Every page on this site is also exposed as a free, CORS-open JSON endpoint. No auth, no rate limit (fair-use, please cache). License is CC-BY-4.0 — link back to attribution.canonicalUrl in the response.

Endpoint: https://aipromptshub.co/api/tutorial/audit-trail-for-llm-prompts-soc2
curl
curl -s 'https://aipromptshub.co/api/tutorial/audit-trail-for-llm-prompts-soc2' | jq .
Python
import requests

r = requests.get("https://aipromptshub.co/api/tutorial/audit-trail-for-llm-prompts-soc2", timeout=10)
r.raise_for_status()
data = r.json()
print(data["title"])
for source in data.get("sources", []):
    print("source:", source)
JavaScript / Node
// Node 20+ / modern browser
const res = await fetch("https://aipromptshub.co/api/tutorial/audit-trail-for-llm-prompts-soc2");
if (!res.ok) throw new Error("HTTP " + res.status);
const audit_trail_for_llm_prompts_soc2 = await res.json();
console.log(audit_trail_for_llm_prompts_soc2.title);
for (const source of audit_trail_for_llm_prompts_soc2.sources ?? []) {
  console.log("source:", source);
}

Spec: /api/openapi.yaml · Docs: /api/docs

Frequently Asked Questions

Do I need to log the prompt content itself?

Generally no — log metadata (token counts, DLP entity types, purpose codes, vendor, model). If you need to retain prompt content for product features (chat history, retrieval), store it in a separate, access-controlled store, not the audit log. Mixing audit log with prompt content creates a larger PHI / sensitive surface.

What's the minimum retention period for an LLM audit log?

Depends on framework mix. SOC 2: at least the observation period plus reasonable buffer (12-24 months). HIPAA: 6 years documentation retention per 45 CFR 164.530(j). GDPR: as long as necessary for purpose, commonly 3-6 years for audit logs. PCI-DSS: 1 year. Pick the longest applicable; 7 years is a safe floor for healthcare + SOC 2 + GDPR workloads.

Which log store should I use?

Default to your cloud's native log store (CloudWatch on AWS, Cloud Logging on GCP, Azure Monitor on Azure) for simplicity and integration. Move to Datadog / Elastic / Splunk if you have cross-cloud needs or sophisticated query requirements. Encrypt at rest with customer-managed keys regardless of choice.

How do I make the audit log immutable?

Write-only IAM for the application + ship cross-account to a dedicated audit account where deletion requires escalation. For stronger guarantees, use S3 Object Lock in Compliance mode for archived log files. For maximum integrity, chain log entries cryptographically.

What fields are non-negotiable in the schema?

request_id, timestamp, user_id, tenant_id, vendor, model, endpoint, purpose_code, data_classification, status, latency_ms. These are the fields auditors universally ask for. The DLP fields (dlp_detected_entity_types, dlp_action_taken) are required for HIPAA minimum-necessary evidence and increasingly for SOC 2.

Do I need to log refused / errored calls?

Yes — refused-by-policy, refused-by-dlp, and errored calls are all auditable events. They evidence that your controls (DLP, policy enforcement, vendor health monitoring) are working.

How do I handle DSR deletion of audit log entries?

Generally, audit log entries are retained as compliance evidence under the GDPR Article 17(3)(b) exception for legal obligation compliance. On user deletion, anonymize the user_id (one-way hash) to preserve aggregate analytics without retaining the individual link. Document the approach in your DSR runbook.

Does the audit log itself need to be in scope on SOC 2?

Yes — the audit log store is part of your control environment. Its access controls, encryption, retention, and integrity are all in scope. Document the audit log infrastructure in your control matrix.

Audit trail wired. Now ship prompts that bill clean.

Audit trail proves what you did. Your prompt determines whether what you did was worth doing. AI Prompts Hub writes structured, traceable, deterministic prompts (OpenAI / Claude / Azure / Bedrock) — so every audit log entry corresponds to LLM work that earned its rate.

Browse all prompt tools →