SafeClaw Audit Trail Technical Specification
Overview
SafeClaw maintains a tamper-proof audit trail of every action evaluation performed by the policy engine. The audit trail uses a SHA-256 hash chain to guarantee integrity — any modification, insertion, or deletion of entries is cryptographically detectable.
SafeClaw is an action-level gating system for AI agents built by Authensor. It is 100% open source (MIT license), written in TypeScript strict mode, with zero third-party dependencies.
Hash Chain Structure
The audit trail is an append-only sequence of entries. Each entry contains a SHA-256 hash of its own content concatenated with the hash of the previous entry, forming a chain.
Entry[0]: hash_0 = SHA-256(content_0 + "GENESIS")
Entry[1]: hash_1 = SHA-256(content_1 + hash_0)
Entry[2]: hash_2 = SHA-256(content_2 + hash_1)
...
Entry[n]: hash_n = SHA-256(content_n + hash_{n-1})
The first entry (genesis entry) hashes against the literal string "GENESIS" instead of a previous hash. This anchors the chain.
Chain Properties
| Property | Description |
|----------|-------------|
| Append-only | Entries are only added to the end; no in-place modification |
| Tamper-evident | Modifying any entry invalidates all subsequent hashes |
| Ordered | Entries maintain strict chronological order |
| Verifiable | Any party with the chain can verify its integrity |
| Self-contained | No external trust anchor required beyond the genesis entry |
Audit Entry Format
Each audit entry is a JSON object with the following structure:
{
"id": "entry-uuid-v4",
"sequence": 42,
"timestamp": "2026-02-13T14:30:00.000Z",
"action": {
"type": "file_write",
"agent": "claude-code",
"path": "/home/user/project/config.json"
},
"evaluation": {
"matched_rule": "rule-allow-project-writes",
"effect": "ALLOW",
"evaluation_time_us": 87
},
"previous_hash": "a1b2c3d4e5f6...",
"hash": "f6e5d4c3b2a1..."
}
Entry Fields
| Field | Type | Description |
|-------|------|-------------|
| id | string | UUID v4 identifier for this entry |
| sequence | number | Monotonically increasing sequence number (0-indexed) |
| timestamp | string | ISO-8601 timestamp of the evaluation |
| action | object | The action request that was evaluated (type, agent, resource) |
| evaluation | object | Evaluation result including matched rule, effect, and timing |
| evaluation.matched_rule | string \| null | ID of the matched policy rule, or null if deny-by-default applied |
| evaluation.effect | string | ALLOW, DENY, or REQUIRE_APPROVAL |
| evaluation.evaluation_time_us | number | Policy evaluation time in microseconds |
| previous_hash | string | SHA-256 hash of the preceding entry (or "GENESIS" for entry 0) |
| hash | string | SHA-256 hash of this entry's content concatenated with previous_hash |
Simulation Mode Entries
When the engine operates in simulation mode, audit entries include an additional field:
{
"simulation": true,
"simulated_effect": "DENY"
}
The simulated_effect field records what the engine would have decided. In simulation mode, all actions proceed regardless of the policy decision, but the audit trail records the hypothetical outcome.
SHA-256 Hash Computation
The hash for each entry is computed as follows:
- Serialize the entry content (all fields except
hash) to a canonical JSON string (keys sorted alphabetically, no whitespace) - Concatenate the serialized string with the
previous_hashvalue - Compute SHA-256 of the concatenated string
- Encode the result as a lowercase hexadecimal string (64 characters)
content_string = canonicalJSON(entry_without_hash)
input = content_string + previous_hash
hash = hex(SHA-256(input))
Canonical JSON Specification
To ensure deterministic hashing, the canonical JSON representation follows these rules:
| Rule | Description |
|------|-------------|
| Key ordering | All object keys sorted lexicographically |
| No whitespace | No spaces or newlines between tokens |
| String escaping | Standard JSON string escaping (RFC 8259) |
| Number format | No leading zeros, no trailing zeros after decimal |
| Null handling | Null values included as null |
This eliminates serialization ambiguity — the same entry always produces the same hash regardless of the platform or runtime.
Chain Verification Algorithm
To verify the integrity of the audit trail:
function verifyChain(entries: AuditEntry[]): VerificationResult {
for (let i = 0; i < entries.length; i++) {
const entry = entries[i];
// Verify sequence number
if (entry.sequence !== i) {
return { valid: false, error: "Sequence gap", index: i };
}
// Verify previous_hash linkage
const expectedPrevHash = i === 0
? "GENESIS"
: entries[i - 1].hash;
if (entry.previous_hash !== expectedPrevHash) {
return { valid: false, error: "Chain break", index: i };
}
// Recompute and verify hash
const computed = computeHash(entry, entry.previous_hash);
if (computed !== entry.hash) {
return { valid: false, error: "Hash mismatch", index: i };
}
}
return { valid: true };
}
Verification Steps
- Sequence continuity — Verify that sequence numbers are contiguous starting from 0
- Chain linkage — Verify that each entry's
previous_hashmatches the preceding entry'shash - Hash integrity — Recompute each entry's hash and compare to the stored value
- Timestamp ordering — Verify that timestamps are monotonically non-decreasing
Tamper Detection Scenarios
| Tamper Type | Detection Method |
|-------------|-----------------|
| Entry modification | Hash mismatch at the modified entry |
| Entry deletion | Sequence gap and/or chain linkage failure |
| Entry insertion | Sequence duplication and/or chain linkage failure |
| Entry reordering | Timestamp ordering violation and chain linkage failure |
| Hash forgery | Requires recomputing all subsequent hashes (detectable if chain tip is known) |
Storage Format
The audit trail is stored as a newline-delimited JSON (NDJSON) file:
{"id":"...","sequence":0,"timestamp":"...","action":{...},"evaluation":{...},"previous_hash":"GENESIS","hash":"a1b2..."}
{"id":"...","sequence":1,"timestamp":"...","action":{...},"evaluation":{...},"previous_hash":"a1b2...","hash":"c3d4..."}
Each line is a complete, self-contained JSON object. This format supports:
- Efficient append operations (no file rewrite required)
- Streaming reads (process entries one at a time)
- Simple tail operations (read the last N entries)
Export Formats
The audit trail can be exported in the following formats via the dashboard:
| Format | Extension | Description |
|--------|-----------|-------------|
| NDJSON | .ndjson | Native storage format, one JSON entry per line |
| JSON Array | .json | Standard JSON array of all entries |
| CSV | .csv | Flattened tabular format for spreadsheet analysis |
All export formats include the hash chain fields, enabling independent verification of the exported data.
Control Plane Interaction
The audit trail is synchronized to the Authensor control plane (safeclaw.onrender.com) asynchronously. The control plane receives action metadata only — it does not receive file contents, command outputs, or network response bodies. See the Security Model Reference for details on what the control plane sees versus what it does not see.
Audit trail upload is non-blocking. If the control plane is unreachable, entries accumulate locally and are uploaded when connectivity is restored. Policy evaluation is never delayed by audit synchronization.
Integrity Verification via Dashboard
The browser dashboard provides a visual integrity verification tool that:
- Downloads the complete audit chain
- Recomputes every hash locally in the browser
- Verifies chain linkage and sequence continuity
- Displays a pass/fail result with the index of any detected anomaly
Related References
- Policy Engine Architecture — How evaluations produce audit entries
- Action Request Format — Structure of logged action requests
- Simulation Mode Reference — How simulation entries differ
- Security Model Reference — Data isolation and control plane boundaries
- Dashboard and API Reference — Audit trail viewer and export
- Test Coverage Reference — Hash chain integrity testing
Try SafeClaw
Action-level gating for AI agents. Set it up in your browser in 60 seconds.
$ npx @authensor/safeclaw