Audit Trail

What you'll accomplish: Enable the audit trail, understand what gets logged, query and filter audit events, and verify chain integrity for compliance audits.

Overview

Hoziron maintains a tamper-evident audit log of all security-relevant operations. Every action — agent lifecycle changes, model interactions, tool invocations, policy enforcement decisions — is recorded in an append-only store with cryptographic chaining.

Enable the audit trail

The audit trail is enabled by default. To customize:

[audit]
enabled = true
max_entries = 100000      # entries retained before pruning (default: 100,000)
segment_max_size_mb = 64  # future: segment rotation threshold
retention_days = 90       # future: segment retention period

What gets logged

CategoryEvents
Agent LifecycleAgent create, start, stop, suspend, resume, delete, competency equip
Model InteractionsAgent invocations (success/error, duration, token usage), model routing decisions
Tool InvocationsEvery MCP tool call (tool name, agent, success/error, execution time)
Trust EnforcementPermission denials, rate limiting, trigger mismatches, cost quota enforcement
System EventsCircuit breaker trips, health check failures, cron executions

Each entry records: timestamp, actor identity, action, target resource, outcome, and a SHA-256 chain hash.

Query audit events

CLI

# Recent events
hoziron security audit --limit 50

# JSON output
hoziron security audit --limit 50 --json

API

# Recent entries
curl http://localhost:4200/security/audit?limit=50 \
  -H "Authorization: Bearer hzk_..."

# Filtered: only trust enforcement events from a specific actor
curl "http://localhost:4200/security/audit?limit=100&category=trust_enforcement&actor=admin-key" \
  -H "Authorization: Bearer hzk_..."

# Filtered: events since a specific time
curl "http://localhost:4200/security/audit?limit=1000&since=2026-06-01T00:00:00Z" \
  -H "Authorization: Bearer hzk_..."

Audit read access requires admin or operator role.

Filter parameters

ParameterDescriptionExample
limitMaximum entries to return (default: 20)100
categoryEvent category prefixagent_lifecycle, trust_enforcement, tool_invocation
actorIdentity of the calleradmin-key, system
sinceOnly entries after this ISO 8601 timestamp2026-06-01T00:00:00Z

Verify integrity

The audit trail uses a Merkle hash chain — each entry's hash incorporates the previous entry's hash, forming a tamper-evident sequence. Any modification breaks the chain.

Self-verification

hoziron security verify

API verification (for third-party auditors)

curl http://localhost:4200/security/verify \
  -H "Authorization: Bearer hzk_..."

Response:

{
  "valid": true,
  "entry_count": 4521,
  "chain_anchor": "0000000000000000000000000000000000000000000000000000000000000000",
  "tip_hash": "a3f8e1c2....",
  "algorithm": "sha256(prev_hash|timestamp|identity|role|action|target|result)",
  "integrity_covers": "timestamp, identity, role, action, target, result",
  "integrity_excludes": "metadata (stored separately for evolvability; not hash-protected)",
  "verification_note": "Each entry's hash = SHA-256 of the pipe-delimited concatenation..."
}

When audit is disabled, the response clearly indicates no verification is possible:

{
  "valid": null,
  "status": "disabled",
  "reason": "audit disabled"
}

Independent verification by auditors

An auditor can verify without trusting the platform:

  1. Export all entries via GET /security/audit?limit=999999
  2. Get chain metadata via GET /security/verify
  3. Sort entries by id ascending
  4. For each entry, compute: SHA-256(prev_hash|timestamp|identity|role|action|target|result)
  5. Verify computed hash equals the entry's hash field
  6. Verify first entry's prev_hash equals chain_anchor
  7. Verify last entry's hash equals tip_hash

If any check fails, tampering has occurred.

Immutability guarantees

The audit store enforces append-only at the database level:

  • UPDATE operations are blocked — SQLite triggers reject any modification to existing entries
  • DELETE operations are blocked — only the internal retention pruning path can remove old entries
  • Merkle chain detects tampering — even if database-level protections are bypassed (e.g., file-level editing), the hash chain breaks and verification fails

Storage

Audit data is stored at $HOZIRON_HOME/data/audit.db. The database uses WAL mode for concurrent read performance.

Retention and pruning

When the entry count exceeds max_entries, the oldest entries are pruned. Before deletion:

  1. The hash of the last pruned entry is saved as a checkpoint
  2. Chain verification anchors from this checkpoint (not genesis)
  3. The chain remains verifiable across pruning events

SIEM integration

For centralized security monitoring, forward audit events to your SIEM:

  • Use JSON log format: set HOZIRON_LOG_FORMAT=json or [logging] format = "json" in config
  • Future: native SIEM export consumer (webhook, syslog) — see roadmap

Best practices

  1. Keep audit enabled in production — it's enabled by default, don't disable it
  2. Verify chain regularly — schedule hoziron security verify in cron or monitoring
  3. Export for compliance — pull audit entries to external storage for long-term retention beyond max_entries
  4. Monitor trust enforcement — filter by category=trust_enforcement to detect attack patterns
  5. Alert on verification failure — a broken chain indicates tampering or corruption

Next steps


Related: