Build audit evidence for every AI decision
With audit storage configured, DVARA records what happened to an AI request: which workspace sent it, which governance controls ran, what they decided, and how the request ended. Use this trail to investigate incidents, answer an auditor, or show that a policy was enforced at a specific time.
Which audit path should you use?
The Open Source distribution and the Enterprise platform produce different audit surfaces. Choose the one that matches your deployment.
| Need | Open Source distribution | Enterprise platform |
|---|---|---|
| HMAC-signed, hash-chained records | Local JSON Lines file; opt-in and off by default | Durable store; enabled in the packaged platform |
| Search and filter in a browser | No | DVARA Console and workspace Portal |
| CSV and JSON export | Read the local file with standard tools | Export the complete filtered result from the Console |
| SIEM delivery | Use your log or file collector | Splunk HEC, CloudWatch Logs, and Kafka integrations |
| Compliance reports | No | SOC 2, HIPAA, GDPR, RBI, and SEBI PDFs |
| MCP and A2A evidence | No | Available when the licensed MCP or A2A plane is active |
The Enterprise audit, SIEM, and report features run without a licence in the Development posture. A licence adds production rights, support, and the MCP and A2A planes.
Record a request with the Open Source distribution
Complete the Open Source distribution quickstart first. It starts the built-in Mock provider, so this example does not send data to an external model.
Set both audit values before starting DVARA:
export DVARA_AUDIT_FILE_PATH="$PWD/var/audit.jsonl"
export DVARA_AUDIT_HMAC_SECRET='<generated-hmac-secret>'
Generate the secret with openssl rand -base64 32. The file path is blank by
default, so the Open Source distribution drops audit events unless you set it. If you set
the path without a secret, or keep the published development secret, DVARA
refuses to start instead of creating evidence that looks trustworthy but is
not.
Send a governed request. The quickstart leaves API-key enforcement off, so this local request does not need an authorization header:
curl -sS http://localhost:8080/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "mock/gpt-4",
"messages": [
{"role": "user", "content": "Summarize the refund policy."}
]
}' | jq
The Mock provider returns a normal OpenAI-compatible response:
{
"id": "mock-6d0d5f08d3dd4aa5b536ba765cb0be63",
"object": "chat.completion",
"created": 1789092000,
"model": "mock/gpt-4",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "This is a mock response"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 12,
"completion_tokens": 5,
"total_tokens": 17
}
}
Now inspect the newest audit record:
tail -n 1 "$DVARA_AUDIT_FILE_PATH" |
jq '{eventType, workspaceId, payload, seq, previousHash, hmac}'
You should see eventType: "GATEWAY_RESPONSE". DVARA writes this event after
each /v1/* request completes. Its payload records the outcome, including the
model, provider, status, latency, token total, policy decision, and error code
when those values apply.
Other controls write their own events. For example, a policy denial writes
POLICY_DENIED, PII enforcement writes PII_DETECTED or PII_REDACTED, and a
blocking guardrail writes GUARDRAIL_BLOCKED. DVARA does not write a separate
GATEWAY_REQUEST event in 1.8.
Which audit events should you monitor?
Start with GATEWAY_RESPONSE. It is the completion record for each governed
model request and carries the outcome needed to join policy, provider, token,
and error evidence. Add the event families that match the controls you have
enabled.
| Event | What it proves | Condition |
|---|---|---|
GATEWAY_RESPONSE | A governed model request completed or failed | Written when audit storage is configured; there is no separate GATEWAY_REQUEST event in 1.8 |
POLICY_DENIED | An active policy refused a request | A matching policy rule returned DENY |
PII_DETECTED / PII_REDACTED / PII_TOKENIZED | Request PII was observed, permanently removed, or replaced with a recoverable token | The workspace's PII action decides; LOG is the default |
PII_RESPONSE_DETOKENIZED | One or more request-created tokens were restored in a non-streaming response | Enterprise auto-detokenization is enabled for the workspace; off by default |
PII_RESPONSE_DETOKENIZE_INCOMPLETE | Auto-detokenization restored only part of the response | Carries tokens_restored, tokens_unresolved, and reason; the response also carries X-Gateway-Pii-Unresolved with the unresolved count |
PII_BLOCKED_STREAMING / GUARDRAIL_BLOCKED_STREAMING / HALLUCINATION_DETECTED_STREAMING | Deferred response enforcement refused a stream | The corresponding response control is enabled with a blocking action |
STREAM_TOO_LARGE_TO_SCAN / STREAM_TOOL_ARGUMENTS_UNENFORCEABLE / STREAM_INCOMPLETE_UNGROUNDED | Deferred delivery was refused because DVARA could not complete the required whole-response check | Written only for the matching bound, tool-argument, or truncated-grounding condition |
STREAMING_ENFORCEMENT_SUMMARY | The final LLM stream enforcement state | Written for governed streams; inspect pii_entity_count, guardrail_detection_count, scan_incomplete, scan_failed, and truncated when present |
SCOPED_RATE_LIMIT_UPDATED / SCOPED_RATE_LIMIT_CLEARED | An operator changed or removed an account or team limit | Enterprise hierarchy editor only |
The Enterprise MCP plane uses one stable family for request and response PII:
| Event | Meaning |
|---|---|
MCP_PII_DETECTED | Request PII was logged or the request was blocked |
MCP_PII_REDACTED | Request PII was removed permanently |
MCP_PII_TOKENIZED | Request PII was replaced with recoverable tokens |
MCP_PII_REDACT_DEGRADED | Request tokenization was selected but no token store was available; action is TOKENIZE despite the retained event name |
MCP_PII_OUTPUT_LEAK | PII was found in a tool response; inspect action to see whether DVARA logged, redacted, or blocked it |
MCP_PII_TOKENIZE_UNAVAILABLE is the HTTP error code returned when request
tokenization cannot run. It is not a second audit event. These events are
available only when the licensed MCP plane is active, and their payloads contain
entity types and counts—not detected values or recovery tokens.
The licensed A2A plane writes to its separate audit chain. It uses one
A2A_PII_DETECTED event for recorded PII enforcement; read its action and
side (request or response) fields instead of looking for action-specific
event names. Every governed A2A stream also writes
A2A_STREAM_SUMMARY. In that payload, pii_enforced_group_count counts
continuation groups containing PII and pii_entity_count counts individual
detections. scan_incomplete, scan_failed, truncated, blocked, and
error_code describe independent parts of the final outcome when present.
Do not configure alerts for POLICY_PROMOTED_TO_WORKSPACE. The current 1.8
runtime has no Console, API, or other production path that emits it. Use the
documented GitOps export and import workflow to move a policy between
workspaces.
What does tamper-evident mean?
Each audit record carries an HMAC signature and the previous record's HMAC. Changing, removing, inserting, or reordering a record breaks verification at that point.
The chain detects changes; it does not prevent changes to the storage:
- The API does not provide a way to update an audit event.
- A person with direct storage access can still delete or replace data.
- A person who also holds the signing secret can rebuild a valid-looking chain.
- Deleting the whole local file destroys the Open Source distribution's evidence.
Protect the audit store and signing secret separately. Keep the Open Source audit file on a persistent volume, restrict access to it, and retain rotated chain segments together.
Search an incident in the Enterprise platform
Open Governance → Audit in the DVARA Console. The default Shared plane contains LLM and MCP events. If the licensed A2A plane is active, choose A2A to search its separate chain.
Filter by workspace, event type, and time range. Expand a row to see its payload and signing fields. To hand the result to another system, export the same filtered set as CSV or JSON. JSON preserves nested payloads and is the better choice for a SIEM or an automated diff.
The following request exports every matching shared-plane event. Replace the base URL, browser session cookie, workspace, and timestamps:
curl -sS \
-H 'Cookie: <flightdeck-session-cookie>' \
'https://flightdeck.acme.example.com/audit/export?workspace_id=payments-prod&event_type=POLICY_DENIED&from=2026-09-01T00%3A00%3A00Z&to=2026-10-01T00%3A00%3A00Z&format=json' \
| jq
The response is a JSON array. Each item has the same public shape:
[
{
"eventId": "0NZP8Q6E5R2KJ",
"timestamp": "2026-09-14T16:42:18.208Z",
"workspaceId": "payments-prod",
"eventType": "POLICY_DENIED",
"payload": {
"policy_id": "production-model-policy",
"rule_id": "deny-unapproved-models",
"reason": "Model is not approved for this workspace",
"workspace_id": "payments-prod",
"api_key": "key_0NZP8MV76C2AT"
}
}
]
Treat eventId as an opaque string. Older records can use UUIDs while newer
records use sortable IDs, and both formats can appear in the same export. Store,
compare, and forward the value without parsing its format.
The payload's api_key is the key's opaque ID, not the gw_... bearer
credential or its display prefix. Usage, cost, per-key budgets, access logs,
analytics, and exports use the same ID, so you can correlate evidence without
copying a secret into it. A request made without an authenticated key records
anonymous. CSV and JSON exports preserve this attribution value.
An empty array means no event matched all filters. Remove one filter at a time, then confirm that you selected the correct plane and time zone.
The Enterprise platform checks the most recent 1,000 chain records every hour
by default. Set dvara.audit.chain-verify.enabled=false only when another
process performs the same check. Change the interval with
dvara.audit.chain-verify.interval-ms and the window with
dvara.audit.chain-verify.max-envelopes. A detected break increments
gateway_audit_chain_gaps_total and writes a warning to the application log;
verification does not stop request traffic.
Keep prompts out of the audit trail by default
The Enterprise platform removes prompt and message content from audit payloads
by default. Set dvara.audit.store-prompts-by-default=true only when your
retention policy permits prompt storage. A workspace can override the install
default with its Store prompts in audit governance setting.
Even when prompt storage is off, the trail keeps structural evidence such as the event type, actor, workspace, decision, model, status, and trace ID when those fields apply. PII audit events record entity types and counts, not the detected values.
Generate a compliance evidence report
Open Governance → Compliance in the Console, then choose a report type,
workspace, and time range. DVARA supports SOC2, HIPAA, GDPR, RBI, and
SEBI reports.
Select Generate, wait for the new row to appear, and download its PDF. The report combines audit events, policy and workspace state, usage evidence, and a chain-integrity result for the selected period. When the licensed A2A plane is active, the report also includes A2A activity and verification of its separate chain.
Generation writes COMPLIANCE_REPORT_GENERATED to the audit trail. Deleting a
saved report writes COMPLIANCE_REPORT_DELETED; downloading it is read-only and
does not create an event.
A DVARA report organizes technical evidence for a review. It does not certify your organization, guarantee compliance, or replace an auditor's assessment.
Send evidence to your SIEM
The Enterprise platform can forward audit events to Splunk HEC, AWS CloudWatch Logs, or Apache Kafka. Export failures do not block primary audit persistence. Configure and test those destinations in SIEM and webhooks.
What should you verify before production?
- Use a strong signing secret and make it available to every process that writes to the same chain.
- Keep the audit store on durable storage and restrict direct access.
- Leave prompt storage off unless a documented retention rule requires it.
- Test a denial and confirm both the governance event and
GATEWAY_RESPONSEappear. - Export a narrow time range and confirm that your downstream system preserves the JSON payload.
- Alert on
gateway_audit_chain_gaps_total; any unexpected increase needs investigation.