Skip to main content
Version: 1.8.0

Build audit evidence for every AI decision

With audit storage configured, DVARA records the outcome of an AI request and the control-specific decisions that emit audit events. A completion record alone does not prove that every optional detector was enabled or executed; combine the request outcome, the relevant control event, and the configuration in force at that time. Use that evidence to investigate an incident or show that a specific policy decision was enforced.

Which audit path should you use?​

Security and evidence events added or clarified in 1.8 include PROVIDER_CREDENTIAL_UNAVAILABLE, PII_ERASURE_SWEPT, MCP_TOOL_POISONING_DETECTED, MCP_INJECTION_DETECTED, A2A_PUSH_URL_BLOCKED, PASSWORD_RESET, PAT_REVOKED_BY_ADMIN, USER_ROLES_CHANGED, WORKSPACE_UPDATED, ROUTE_CANARY_SPLIT_UPDATED, ROUTE_CANARY_METRICS_RESET, ROUTE_SHADOW_METRICS_RESET, SEMANTIC_CACHE_CLEARED, MODEL_PRICING_CREATED, MODEL_PRICING_UPDATED, MODEL_PRICING_DELETED, TOKEN_CAP_BLOCK_TRIGGERED, MCP_CAP_BLOCK_TRIGGERED, PER_CALL_COST_BLOCKED, and BUDGET_COLD_START_REFUSED. Alert on the event that matches the configured control; an event's absence does not prove the control ran.

The Open Source distribution and the Enterprise platform produce different audit surfaces. Choose the one that matches your deployment.

For an Open Source file chain, run the packaged FileAuditChainVerifier with the same DVARA_AUDIT_HMAC_SECRET used to write the file. It exits 0 only when at least one line verifies, 1 on a broken line, and 2 when nothing was checked, so an empty file cannot produce a misleading valid result. The Open Source quickstart has the command.

NeedOpen Source distributionEnterprise platform
HMAC-signed, hash-chained recordsLocal JSON Lines file; opt-in and off by defaultDurable store; enabled in the packaged platform
Search and filter in a browserNoDVARA Flightdeck
CSV and JSON exportRead the local file with standard toolsExport the complete filtered result from Flightdeck after two-person approval
SIEM deliveryUse your log or file collectorSplunk HEC, CloudWatch Logs, and Kafka integrations
Compliance reportsNoSOC 2, HIPAA, GDPR, RBI, and SEBI PDFs
MCP and A2A evidenceNoYes, from the Enterprise MCP and A2A planes

A compliance report generated without a licence says "Non-production licence" in its footer. From 1.8.3, one generated more than 14 days after the licence expired says "Expired licence".

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 with the key minted by the quickstart:

curl -sS http://localhost:8080/v1/chat/completions \
-H "Authorization: Bearer $DVARA_API_KEY" \
-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.

EventWhat it provesCondition
GATEWAY_RESPONSEA governed model request completed or failedWritten when audit storage is configured; there is no separate GATEWAY_REQUEST event in 1.8. From 1.8.5 a call on /v1/messages that sent an anthropic-beta header records it as anthropic_beta; otherwise the record is the same for /v1/messages and /v1/chat/completions
POLICY_DENIEDAn active policy refused a requestA matching policy rule returned DENY
PII_DETECTED / PII_REDACTED / PII_TOKENIZEDRequest PII was observed, permanently removed, or replaced with a recoverable tokenThe workspace's PII action decides; LOG is the default
PII_RESPONSE_DETOKENIZEDOne or more request-created tokens were restored in a non-streaming responseEnterprise auto-detokenization is enabled for the workspace; off by default
PII_RESPONSE_DETOKENIZE_INCOMPLETEAuto-detokenization restored only part of the responseCarries 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_STREAMINGDeferred response enforcement refused a streamThe corresponding response control is enabled with a blocking action
STREAM_TOO_LARGE_TO_SCAN / STREAM_TOOL_ARGUMENTS_UNENFORCEABLE / STREAM_INCOMPLETE_UNGROUNDEDDeferred delivery was refused because DVARA could not complete the required whole-response checkWritten only for the matching bound, tool-argument, or truncated-grounding condition
STREAMING_ENFORCEMENT_SUMMARYThe final LLM stream enforcement stateWritten for governed streams; inspect pii_entity_count, guardrail_detection_count, scan_incomplete, scan_failed, and truncated when present
MCP_EXTENSION_DENIED / MCP_DEPRECATED_FEATURE_USEDFrom 1.8.4: an MCP client asked for an extension its workspace does not grant, or used deprecated Roots, Sampling or LoggingEnterprise MCP plane; recorded at most once a day per client (and per feature)
WORKSPACE_MCP_EXTENSIONS_UPDATEDFrom 1.8.4: a workspace admin changed the MCP extension allow-list in the FlightdeckFlightdeck
AGENT_SESSION_KILLEDFrom 1.8.5: an operator killed a session by workspace and ID with the Kill a session by id formFlightdeck (owner, policy-admin) or Flightdeck (admin, developer); carries scope: all_planes, like MCP_SESSION_KILLED and A2A_SESSION_KILLED from 1.8.5
SESSION_KILL_ENFORCEDFrom 1.8.5: a Gateway refused a killed session for the first time on one planeOne per session, plane and Gateway, so a retrying agent does not flood the chain; carries plane (llm, mcp, a2a), pod and source (local, relay, deny_list)
MCP_SERVER_DISCOVEREDFrom 1.8.5: a client asked the native /mcp endpoint what the server can do (server/discover)Enterprise MCP plane
MCP_DEPRECATED_TRANSPORT_USEDFrom 1.8.5: DVARA reached an upstream server over the legacy HTTP+SSE transportAt most once a day per server, until the 2027-07-28 sunset
MCP_ARGUMENTS_TOO_LARGEFrom 1.8.5: a tool call's arguments were over the size limit and the call was refusedDefault limit 1 MiB; the call also gets a tool-call row with decision DENY
MCP_INPUT_REQUESTED / MCP_INPUT_RESPONDEDFrom 1.8.5: a server asked the client for input, and the client answered on its retryJoined by the digest of the server's requestState; never carries the request's text
API_KEY_AGENT_BOUNDAn API key was bound to an agent (Acts as agent)From 1.8.5 it carries may_start_chains
SCOPED_RATE_LIMIT_UPDATED / SCOPED_RATE_LIMIT_CLEAREDAn operator changed or removed an account or team limitEnterprise hierarchy editor only

The Enterprise MCP plane uses one stable family for request and response PII:

EventMeaning
MCP_PII_DETECTEDRequest PII was logged or the request was blocked
MCP_PII_REDACTEDRequest PII was removed permanently
MCP_PII_TOKENIZEDRequest PII was replaced with recoverable tokens
MCP_PII_REDACT_DEGRADEDRequest tokenization was selected but no token store was available; action is TOKENIZE despite the retained event name
MCP_PII_OUTPUT_LEAKPII 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 written only by the Enterprise MCP plane, and their payloads contain entity types and counts—not detected values or recovery tokens.

The Enterprise 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. From 1.8.5 a stream the caller hung up on part-way is recorded with error_code A2A_STREAM_INTERRUPTED, and a stream the peer broke off with A2A_UPSTREAM_TRUNCATED.

From 1.8.5 a peer's push notification goes through the Gateway. Each one writes an A2A_PUSH_NOTIFICATION event to the A2A chain, whatever the outcome. Read its outcome (delivered, withheld, duplicate, delivery_failed or refused) and pii_action. A workspace that keeps direct delivery (a2a.push.delivery=direct) gets no such event, because DVARA never sees the notification.

From 1.8.5 a Gateway with no database sends each A2A audit event to your SIEM once, from the Gateway that wrote it.

Do not configure alerts for POLICY_PROMOTED_TO_WORKSPACE. The current 1.8 runtime has no Flightdeck, 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.

When Enterprise audit archival is active, cost and token-usage records use the workspace audit retention or a fixed 400-day floor, whichever is longer. This keeps monthly budgets, usage reports, and chargeback calculations from losing their source records. See Archive Enterprise audit evidence for the shipped-image limitation and complete archive settings.

Search an incident in the Enterprise platform​

Open Governance → Audit in the DVARA Flightdeck. The default Shared plane contains LLM and MCP events. Choose A2A to search the A2A plane's 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, request an export of the same filtered set as CSV or JSON and give a reason. JSON preserves nested payloads and is the better choice for a SIEM or an automated diff.

A different authorized person reviews the exact plane, workspace, event type, time range, and format under Governance → Approvals. Approval does not start the download: the original requester returns to the audit page and executes the export before its 15-minute approval expires. This keeps one person from selecting and releasing sensitive evidence without review. If any filter or the format changes, Flightdeck refuses the approval and requires a new request. See Govern sensitive changes with approvals for recent-sign-in requirements, expiry, and the audit events written for the decision and execution.

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.

Use the bound key for the verification window

Today, set dvara.audit.chain-verify-max-envelopes (hyphens throughout). The dotted dvara.audit.chain-verify.max-envelopes spelling above does not bind, even though the neighbouring enabled and interval-ms settings do. A rename to one consistent spelling is tracked; this page will use that spelling after the runtime change lands.

Keep prompts out of the audit trail by default​

The Enterprise platform removes prompt and message content from audit payloads, and in 1.8.1 there is no way to keep them: prompt storage is not implemented. dvara.audit.store-prompts-by-default and the workspace's Store prompts in audit setting both bind, but nothing writes a prompt, so turning either on keeps nothing. The Gateway says so in a startup warning, and again once for each workspace that has it on.

Storage is held back because the audit chain signs every payload key and the tables are append-only, so a prompt written there could never be deleted — not on a retention sweep, and not on an erasure request. The design that can delete them keeps a hash in the signed event and the text in a separate table, and it is planned for 1.9.0.

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 Flightdeck, 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 A2A plane carries traffic, the report also includes A2A activity and verification of its separate chain.

Access-control sections count both the built-in and SAML LOGIN_SUCCESS / LOGIN_FAILED events and the SSO AUTHENTICATION_SUCCESS / AUTHENTICATION_FAILURE pair, and identify the source. A workspace-scoped report counts only that workspace's events, including its GDPR event total.

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.

Evidence is not certification

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?​

  1. Use a strong signing secret and make it available to every process that writes to the same chain.
  2. Keep the audit store on durable storage and restrict direct access.
  3. Leave prompt storage off unless a documented retention rule requires it.
  4. Test a denial and confirm both the governance event and GATEWAY_RESPONSE appear.
  5. Export a narrow time range and confirm that your downstream system preserves the JSON payload.
  6. Alert on gateway_audit_chain_gaps_total; any unexpected increase needs investigation.