Audit Trail
Hash-chain, Ed25519 verification, retention, and optional anchors.
Entries produced by Rensei's current audit append path are linked into a per-workspace SHA-256 hash chain and carry per-workspace Ed25519 signatures. Retained history can include legacy unsigned entries. A holder of a supplied segment can recompute entry hashes, check predecessor links, and verify signatures where present against the published keys.
Signature presence is not verification. Those checks provide tamper-evidence for the supplied segment only. They do not establish that every event was captured, that the segment is the full retained history, that an event was true when recorded, that data outside the segment was retained, or that the segment was externally timestamped.
Hash-chain integrity
Entries from the current append path carry the following integrity fields:
| Field | Description |
|---|---|
entryHash | SHA-256 of the canonical entry fields, including the previous hash |
prevHash | The entryHash of the immediately preceding entry for this workspace |
sequenceNumber | Monotonically increasing per-workspace counter |
signature | Base64-encoded Ed25519 signature over the entry-hash bytes; nullable on legacy rows |
signingKeyId | Identifier of the workspace public key needed to check the signature; nullable on legacy rows |
The first entry in a new workspace chain uses a 64-zero previous-hash sentinel. For a supplied contiguous segment, recomputing the hashes detects a changed entry or a broken predecessor link. It does not show whether entries before or after that segment were omitted.
Canonical JSON
Before hashing, the event payload is serialized with canonicalJsonStringify - a deterministic JSON serializer that sorts object keys alphabetically. This ensures consistent hashes regardless of key insertion order.
Chain verification
Verify the retained segment available to the authenticated organization:
curl "https://app.rensei.ai/api/audit/verify" \
-H "Authorization: Bearer rsk_live_..."
# Returns:
# {
# "valid": true,
# "eventsChecked": 0,
# "chainBreakDetected": false,
# "chainBreaks": [],
# "merkleRoot": "..."
# }The route derives organization scope from the authenticated session or token; it does not accept a caller-selected workspace in the request body. A valid: true result means the explicit verifier's checks passed over the entries it processed. It is not a statement about capture completeness, omitted history, truth at capture, retention outside the processed segment, scheduled monitoring, or external anchoring.
For a public, one-entry verification exercise, use the redacted signed sample and the published verification protocol and catalog.
Optional operator-triggered anchoring
The platform contains an admin-triggered path that can submit a Merkle root to a configured RFC 3161 timestamp endpoint. It is not a periodic or scheduled guarantee, and external timestamp anchoring is not part of the current public sample or published proof.
How Merkle anchoring works
- The operator requests a Merkle root over the currently retained workspace entries in sequence order.
- The root hash and a fresh nonce are submitted as an RFC 3161 timestamp request.
- Before storage, the response parser checks granted status, the message imprint, and the nonce against that request.
- The anchor verifier later recomputes the retained prefix covered by
merkleLeafCountand rechecks the stored response's message imprint.
The current verifier does not validate the timestamp token's CMS signature or certificate chain. A result marked local-fallback confirms only the recomputed Merkle root and is explicitly not external timestamp proof. Even a verified timestamp response covers the retained prefix supplied to the anchor operation; it does not prove event capture or full-history completeness.
TSA configuration
The platform operator configures the timestamp endpoint through AUDIT_TSA_URL. Production refuses an anchor request when that value is absent. The FreeTSA endpoint is a development/test default only; this page makes no claim that production anchoring is configured or active.
Merkle root API
# Compute the current retained-tree root for the authenticated organization
curl "https://app.rensei.ai/api/audit/merkle-root" \
-H "Authorization: Bearer rsk_live_..."
# Get an inclusion proof for a specific event
curl "https://app.rensei.ai/api/audit/inclusion-proof?eventId=1234" \
-H "Authorization: Bearer rsk_live_..."The Merkle-root and inclusion-proof responses are not external anchors by themselves. An administrator can call POST /api/audit/anchor only when an external endpoint is configured, and GET /api/audit/anchors/{id}/verify reports whether the stored response passed the implemented checks and whether it is an external response or a local fallback.
Signing keys
Entries produced by the current append path are signed with a per-workspace Ed25519 key managed by the platform operator. Retained legacy entries can have no signature or signing-key identifier. The corresponding public keys are published as RFC 7517 JWKS documents so a holder can explicitly verify signatures that are present.
# Fetch the public JWKS for a workspace
curl https://app.rensei.ai/.well-known/audit-keys/{workspace_id}.json
# Returns an RFC 7517 JWKS (EdDSA / Ed25519):
# { "keys": [{ "kty": "OKP", "crv": "Ed25519", "alg": "EdDSA", "use": "sig",
# "kid": "key_01abc...", "x": "base64url-public-key",
# "rensei:workspace_id": "ws_...", "rensei:created_at": "...", "rensei:revoked_at": null }] }The discovery and verification protocol are published at https://rensei.ai/.well-known/audit-keys.json. Finding a signature and key does not make an entry verified; the verifier must recompute the entry hash, select the referenced key, check the Ed25519 signature, and separately inspect the predecessor linkage for the supplied segment.
The key-rotation route revokes the old key, provisions the replacement, and then attempts to append an audit.key_rotated entry using the new key. See Audit Keys JWKS for the verification implications.
Crypto-shredding (GDPR compliance)
The break-glass crypto-shred API can destroy the organization data-encryption key for encrypted audit payload material while retaining hash and signature metadata used for integrity checks. It derives organization scope from the authenticated caller and requires both an organization administrator and a Rensei operator. A completed shred is irreversible. Its presence does not change the proof limits above.
Shredding a workspace
curl -X POST https://app.rensei.ai/api/audit/crypto-shred \
-H "Cookie: <authenticated admin/operator session>" \
-H "Content-Type: application/json" \
-d '{ "confirm": true }'Crypto-shredding is irreversible. The route attempts to append an audit.crypto_shred entry with action: shred_initiated before attempting key destruction. A record, when present, proves initiation only; only the successful API result or the authenticated status route confirms that the workspace key was shredded.
Storage and read boundary
audit_events is currently an ordinary, non-partitioned PostgreSQL table. Authenticated audit reads use application-level organization/workspace authorization and query filtering. Project filtering is route-dependent and applies only on routes that accept project scope. The inspected audit-read routes are not Cedar-gated, and this page does not claim production database row-level security as their live runtime enforcement boundary. Use the documented from, to, entity, limit, and offset filters to bound API reads; there is no partition-pruning claim.
SIEM delivery
After a successful append, the platform starts non-blocking fan-out to configured SIEM destinations. Delivery is fire-and-forget: a destination failure is logged and does not roll back the recorded entry. This is a delivery attempt, not a guarantee that every destination received every entry. See Observability for configuration.
Retention policy
Retention is configured per organization. The retention workflow exports an eligible contiguous prefix to cold storage and verifies its archive checksum before rows become purgeable from hot storage. It attempts to append audit.retention_archive_created when an archive is produced. Verification of the hot retained segment does not prove that older archived material was supplied to the verifier.
Event type taxonomy
The event taxonomy includes these representative categories:
| Category | Examples |
|---|---|
| Agent lifecycle | agent.spawned, agent.completed, agent.failed |
| Identity | user.login, user.logout, user.invited, user.deprovisioned |
| Approval gates | approval.gate_created, approval.decision_submitted, approval.gate_resolved |
| Policy | policy.created, policy.evaluated, policy.archived |
| Audit integrity | audit.chain_break_detected, audit.key_rotated, audit.anchored |
| Access | sso.connection_created, scim.user_provisioned, m2m.token_issued |
| Workflow | workflow.published, workflow.deployed, workflow.instance_started |
| Compliance | compliance.artifact_generated |
Related pages
- Observability - OTel, Sentry, and SIEM destination setup
- BFSI Compliance - how audit events feed regulatory compliance artifacts
- Cedar Policies -
policy.evaluatedevents in the audit trail - Audit API - REST endpoints, explicit verification, and proof limits