Skip to content

Audit Log Verification

Every Arbitex audit log entry is protected by an HMAC chain. The chain cryptographically links each entry to the one before it, so that any modification, deletion, or reordering of entries is detectable without requiring access to the original request data. This guide explains the chain construction, how to run verification against the API, and how to interpret the results.

Audit log integrity is enforced using HMAC-SHA256. When an audit entry is written, Arbitex computes an HMAC over the entry’s content fields and the HMAC of the immediately preceding entry. The resulting digest is stored alongside the entry. Because each entry incorporates the previous digest, the entries form a tamper-evident chain: altering any entry invalidates its HMAC and breaks the chain link into every subsequent entry.

The HMAC chain proves:

  • Integrity — the content of each entry has not been modified since it was written.
  • Completeness — no entries have been deleted from the middle or end of the sequence.
  • Ordering — entries have not been reordered; the chain is valid only in created_at ASC order.

The chain does not prove that entries were never written with incorrect data at capture time. It proves only that the stored entries have not changed after the fact.

Three fields are injected into each audit log entry by the integrity service:

FieldTypeDescription
hmacstringHMAC-SHA256 hex digest for this entry
previous_hmacstringHMAC of the preceding entry, or the genesis sentinel for the first entry
hmac_key_idstringIdentifier of the HMAC key used to compute hmac

hmac_key_id corresponds to the key ID embedded in the AUDIT_HMAC_KEY environment variable. It is stored with the entry so that verification can select the correct key if you rotate keys over time.

The first entry in the chain has no predecessor. In place of a real previous_hmac, it carries the genesis sentinel: 64 consecutive zero characters.

0000000000000000000000000000000000000000000000000000000000000000

This value is a fixed constant, not a key or secret. Its presence confirms that an entry is the chronological first in the chain.

The HMAC is computed over a canonical message string assembled from three components:

key_id + ":" + json.dumps(content, sort_keys=True, default=str) + previous_hmac

Where:

  • key_id is the string identifier from hmac_key_id
  • content is the entry’s field dictionary, with hmac, previous_hmac, and hmac_key_id excluded
  • json.dumps uses sort_keys=True to ensure deterministic field ordering; default=str serializes any non-JSON-native types as strings
  • previous_hmac is appended as a plain hex string, not as a JSON value

The fields included in content for HMAC computation are:

Field
timestamp
user_id
action
conversation_id
model_id
provider
prompt_text
response_text
token_count_input
token_count_output
cost_estimate
latency_ms
metadata
tenant_id
ip_address

ip_address is always null — it is included in the HMAC computation for schema stability but is never populated.

The chain is ordered by created_at ASC. Verification must process entries in this order to correctly thread previous_hmac values through the sequence.

Verification is performed through a single API call. No request body is required. The endpoint recomputes the HMAC for every entry in the chain and checks that each previous_hmac matches the stored hmac of the preceding entry.

Prerequisites:

  • Your API token must have the admin role.
  • The AUDIT_HMAC_KEY environment variable must be configured on the Arbitex server.

Run verification:

Terminal window
curl -X POST https://your-arbitex-instance.example.com/api/admin/audit/verify \
-H "Authorization: Bearer your-arbitex-api-key" \
-H "Content-Type: application/json"

The endpoint accepts no request body. The response is returned synchronously. For large audit logs, the request may take several seconds to complete.

The response is a JSON object with three fields:

{
"valid": true,
"total_entries": 48291,
"errors": []
}
FieldTypeDescription
validbooleantrue if the chain is intact across all entries; false if any integrity violation was detected
total_entriesintegerNumber of entries evaluated during this verification run
errorsarray of stringsHuman-readable descriptions of each integrity violation; empty when valid is true

When valid is false, errors contains one entry per violation. Review each error message to determine the scope and location of the problem. A single tampering event typically produces one error at the modified or deleted entry and cascading errors on every subsequent entry in the chain.

If AUDIT_HMAC_KEY is not configured on the server, the endpoint returns HTTP 400 before performing any verification. This is a configuration error, not an integrity failure.

The verification engine identifies four categories of integrity violation. Sample error messages are illustrative; exact wording may include entry identifiers and timestamps from your audit log.

An entry’s content was changed after it was written. The stored hmac no longer matches the HMAC recomputed from the current field values.

Hash mismatch on entry id=ae4f2c1b at 2026-03-07T11:42:08Z: stored hmac does not match recomputed value

The entry at the reported position is suspect. All subsequent entries are also suspect because their previous_hmac chain was seeded from the modified entry’s HMAC.

An entry was removed from the chain. The previous_hmac on the entry following the deletion point does not match the hmac of the entry now preceding it.

Chain gap on entry id=9d3e7a22 at 2026-03-07T11:42:09Z: previous_hmac does not match hmac of preceding entry

The deletion is detectable at the first entry after the gap. Entries before the gap remain valid; entries after the gap are suspect because the chain origin for that segment is broken.

Entries were moved to a different position in the sequence. The previous_hmac of the displaced entry does not match the hmac of the entry that now precedes it.

Chain gap on entry id=7b1c4d09 at 2026-03-07T11:42:11Z: previous_hmac does not match hmac of preceding entry

Reordering produces the same error signature as deletion. Both represent a broken chain link. Distinguishing between the two requires cross-referencing with your SIEM archive.

An entry inserted into the middle of the chain breaks the previous_hmac link on the entry that originally followed that position.

Chain gap on entry id=2f8a6b44 at 2026-03-07T11:42:10Z: previous_hmac does not match hmac of preceding entry

An injected entry cannot carry a valid HMAC because the attacker would need the HMAC secret to recompute a consistent chain from the injection point forward.

Arbitex provides three export formats for audit log data. All formats include the hmac, previous_hmac, and hmac_key_id fields so that offline verification is possible independent of the API endpoint.

JSON

Full event structure as a JSON array. Suitable for programmatic processing, offline HMAC recomputation, and long-term archival. Each array element is a complete audit entry object.

CSV

Flattened field representation. Suitable for spreadsheet analysis and ad-hoc querying. Nested objects (such as metadata) are serialized to string representations.

SIEM-ready

Structured for direct SIEM ingestion. Events are formatted for compatibility with OCSF-aware platforms and include the HMAC fields alongside the normalized event schema.

Export is available through the admin API. See Audit log for export endpoint details and query parameters.

AUDIT_HMAC_KEY environment variable

The HMAC key must be set in the AUDIT_HMAC_KEY environment variable on the Arbitex server. This variable supplies both the key material and the key identifier used in hmac_key_id. If this variable is absent, new entries are written without HMAC fields and the verification endpoint returns HTTP 400.

Rotate this key according to your key management policy. After rotation, entries written before the rotation carry the old hmac_key_id; the verification engine uses hmac_key_id to select the correct key for each entry. Historical keys must remain available to the server for verification to succeed across rotation boundaries.

Admin role

The POST /api/admin/audit/verify endpoint requires an API token with the admin role. Standard user tokens receive HTTP 403.

Key escrow

Store HMAC keys outside the Arbitex platform — in your SIEM, a secrets manager, or an HSM. If the platform were compromised, an attacker with access to both the stored entries and the HMAC key could recompute a valid-appearing chain. Out-of-band key storage is what makes the tamper evidence meaningful.

  • Audit log — audit entry fields, export API, retention, and SIEM integration
  • DLP Overview — how the 3-tier DLP pipeline produces findings recorded in audit entries
  • Policy Engine overview — how policy evaluation fields are generated