Your OpenClaw assistant just deleted a file, sent an email, or ran a shell command on your machine. Can you prove what it did? When? Authorized by whom?
Standard log files don't answer that. They can be edited. They can be rotated. They can be deleted. After an incident, "the agent did X" is your word against the runtime that produced the log.
This post walks through adding cryptographic audit trails to OpenClaw using @signet-auth/openclaw-plugin. Every tool call gets:
- An Ed25519 signature over the canonical action payload (RFC 8785 JCS → SHA-256 → Ed25519)
- A hash-chained entry in
~/.signet/audit/*.jsonl— deletion or reordering breaks the chain - Optional policy enforcement (deny dangerous tools before they run)
- Optional encryption of tool params at rest
Total setup time: under a minute.
What you need
- OpenClaw (
>=2026.3.24-beta.2) — the gateway you already run - The
signetCLI on$PATH. Install viacargo install signet-cli, or grab a release binary - Two minutes
That's it.
Step 1: Create a signing identity
The plugin signs with a local Ed25519 key. Generate one:
signet identity generate --name openclaw-agent --owner you@example.com
This writes the keypair to ~/.signet/identities/openclaw-agent/. The private key stays on disk; the public key is what verifiers (auditors, you, anyone) use to check signatures later.
If you want the key passphrase-protected, add --passphrase. We'll set the passphrase env var below.
Step 2: Install the plugin
openclaw plugins install @signet-auth/openclaw-plugin
OpenClaw checks ClawHub first, falls back to npm.
Step 3: Configure
Add the plugin entry to ~/.openclaw/config.json:
{
"plugins": {
"entries": {
"signet": {
"config": {
"keyName": "openclaw-agent",
"target": "openclaw://gateway/local"
}
}
}
}
}
Two fields are enough to get started. Everything else has sensible defaults.
If your key is passphrase-protected, export the passphrase before launching the gateway:
export SIGNET_PASSPHRASE='...'
openclaw start
Step 4: Use OpenClaw normally
Run any task that exercises tools — file operations, web search, shell commands, anything. Every tool call now produces a signed receipt before execution. Tool errors are logged. Nothing in your workflow changes.
While OpenClaw runs, watch the gateway log for lines like:
[signet] signed file_read (call=tc_abc123 session=ses_xyz789) → rec_a1b2c3d4...
[signet] signed shell_exec (call=tc_def456 session=ses_xyz789) → rec_e5f6a7b8...
Each rec_... is a receipt id derived from the signature itself.
Step 5: Verify the audit trail
After OpenClaw has done some work, verify the chain:
signet audit --verify
Output:
Hash chain integrity: valid (records=42)
Signature verification: 42 / 42 valid
That second line is the cryptographic guarantee: 42 receipts, every one of them signed by the key whose public half lives in ~/.signet/identities/openclaw-agent/openclaw-agent.pub.json. Modify any field of any receipt and the verification fails. Delete a record and the chain breaks.
To browse what your assistant actually did:
signet explore
Press a tool name to see the full action payload, params, timestamp, and the run id that ties together the before_tool_call and after_tool_call events.
What a receipt looks like
Each line of ~/.signet/audit/audit.jsonl is one record. The signed receipt inside looks like this:
{
"v": 1,
"id": "rec_a1b2c3d4e5f6a7b8...",
"action": {
"tool": "shell_exec",
"params": { "command": "git status" },
"params_hash": "sha256:...",
"target": "openclaw://gateway/local",
"transport": "stdio"
},
"signer": {
"name": "openclaw-agent",
"pubkey": "ed25519:...",
"owner": "you@example.com"
},
"ts": "2026-04-26T14:30:00.000Z",
"nonce": "rnd_...",
"sig": "ed25519:..."
}
The signature covers the entire payload. Modify action.params.command from "git status" to "rm -rf /" and the signature stops verifying.
Adding policy enforcement
Audit-after-the-fact is good. Blocking dangerous calls before they run is better.
Create a policy at ~/.signet/policies/openclaw.yaml:
version: 1
name: openclaw-safe
default_action: allow
rules:
- id: deny-rm-rf
match:
tool: shell_exec
params:
command:
contains: "rm -rf"
action: deny
reason: "destructive command — never run without human approval"
- id: rate-limit-network
match:
tool:
one_of: [http_request, fetch_url]
action: rate_limit
rate_limit:
window_secs: 60
max_calls: 10
Wire it into the plugin config:
{
"plugins": {
"entries": {
"signet": {
"config": {
"keyName": "openclaw-agent",
"target": "openclaw://gateway/local",
"policy": "~/.signet/policies/openclaw.yaml"
}
}
}
}
}
Restart OpenClaw. When the policy denies a call, you'll see:
[signet] policy denied shell_exec: destructive command — never run without human approval
OpenClaw skips the tool call entirely. The denial itself isn't signed — that's by design. Only allowed actions produce receipts. The denial is logged at warn level so it's still observable.
What this gives you
| Without Signet | With Signet |
|---|---|
| "OpenClaw ran shell_exec" — log entry, editable | Ed25519 signature proving exactly what command, when, by which key |
| Ordering can be falsified | Hash chain breaks if any entry is removed or reordered |
| Trust your local logs | Verify offline with just the public key |
| No regulatory mapping | Maps to EU AI Act Article 12 "automatic event logging" requirement (effective August 2026) |
Verifying as an external auditor
If someone else needs to verify your audit log — a security team, a regulator, you on a different machine — they only need:
- The audit log file (
~/.signet/audit/audit.jsonl) - The agent's public key (
~/.signet/identities/openclaw-agent/openclaw-agent.pub.json)
No private key. No access to the OpenClaw runtime. They run:
signet audit --verify --keys-dir ./received-keys
If the chain is intact and every signature checks out, the audit log is authentic. If anyone tampered with anything, verification fails at the modified record.
This is the property that "we keep good logs" can never give you.
What's next
The plugin is open source (Apache-2.0 OR MIT). If you want:
- Bilateral co-signing: server-side keys signing alongside the agent for two-party non-repudiation. Already in Signet core; can be wired into OpenClaw via a follow-up plugin.
- Trust bundles: pin a published bundle of trusted public keys so verifiers don't need to track keys out-of-band.
-
Encrypted params: set
encryptParams: truein the plugin config to wrapaction.paramsin an XChaCha20-Poly1305 envelope keyed off the signing key. The signature chain stays verifiable; only key holders see the params.
Repo: https://github.com/Prismer-AI/signet
Plugin: https://github.com/Prismer-AI/signet/tree/main/packages/signet-openclaw-plugin
Issues: https://github.com/Prismer-AI/signet/issues
If you build something with this, I'd love to know. The OpenClaw maintainers in particular — feedback on the hook integration and security audit collector behavior would be valuable.
Top comments (0)