@vorim/verify
v0.5.1
Published
Offline verifier for Vorim audit bundles — no network, no Vorim API call, no telemetry.
Maintainers
Readme
@vorim/verify
Offline Agent Verification — no vendor, no blockchain.
vorim-verify lets any party independently verify what an AI agent is, what it was permitted to do, and what it did — using only built-in cryptography. No vendor in the loop. No blockchain. No network call.
Every identity provider for AI agents today (Okta, Microsoft Entra, Ping, CyberArk, the LLM platforms) answers "is this agent allowed?" by checking a token against their server. Take the server away and the proof evaporates. vorim-verify is the opposite: the agent's identity, its attenuated delegation chain, and its signed audit trail are all checked against public keys carried inside the bundle itself. A regulator, a customer, or a counterparty can confirm the whole story with the issuer offline — or gone entirely.
It checks three things, offline:
- Identity — each event/link is signed by the agent's own Ed25519 key (carried in the bundle, fingerprint-pinned).
- Delegation — a multi-hop
A → B → Cchain where authority provably only narrows at each hop. See Delegation Receipts. - Audit — an append-only, hash-linked, signed event ledger that has not been edited since export.
Install
npm install -g @vorim/verifyOr run without installing:
npx @vorim/verify bundle.jsonUsage
vorim-verify bundle.json # verify a bundle file
cat bundle.json | vorim-verify - # read from stdin
vorim-verify --explain bundle.json # per-event verdicts
vorim-verify --receipts bundle.json # print the delegation receipt (attenuation tree)
vorim-verify --json bundle.json # machine-readable JSON outputExit codes: 0 ok, 1 verification failed, 2 CLI / IO error.
Example output:
vorim-verify: OK
bundle_version : vaip-v0
manifest : OK (sha256:8ff556a7222f...)
events total : 247
verified : 247
unsigned : 0
bad signature : 0
unknown agent : 0
malformed : 0Delegation Receipts
A delegation receipt is the proof artifact for Vorim's attenuated multi-hop delegation. When an agent hands authority to another agent (A → B), and that agent hands a subset onward (B → C), the receipt shows — hop by hop — exactly how authority narrowed, and confirms offline that it could only ever narrow, never widen.
This is the capability the incumbents do not have. Okta and Auth0 do OAuth scope grants; Microsoft Entra does on-behalf-of impersonation; Google A2A explicitly defines no way to cap what a downstream agent can spend. None of them produce a portable, offline-checkable record of an attenuated delegation chain. Vorim does.
vorim-verify --receipts bundle.json═══════════════════════════════════════════════════════════════
DELEGATION RECEIPT (offline-verified — no vendor, no blockchain)
═══════════════════════════════════════════════════════════════
Chain chain_demo_001
✓ VERIFIED
depth: 2 hops
┌─ hop 1: agent_A → agent_B
scopes: [agent:read, agent:write, agent:execute]
sub-delegation budget remaining: 2
valid until: 2027-06-01T00:00:00Z
└─ hop 2: agent_B → agent_C
scopes: [agent:read]
↓ dropped: [agent:write, agent:execute] (authority narrowed)
sub-delegation budget remaining: 1
valid until: 2027-06-01T00:00:00Z
Each hop above was checked offline: signature under the delegator's
public key, chain continuity (no splicing), depth cap, and scope ⊆ parent.
Authority can only narrow down the chain; it can never widen.Each hop is checked with the same cryptography as the rest of the bundle: the link's signature must verify under the delegator's public key, the chain must be continuous (no spliced links), the sub-delegation depth cap must be honoured, and each link's scopes must be a subset of its parent's. A widened or forged chain is reported as broken, not drawn.
What verification proves
For every event marked verified:
- The bundle has not been edited since the API exported it. The bundle's SHA-256 manifest must match the bytes of
events + agentsexactly. - The agent identified in the event is the one that authored the bytes recorded. The event's
ed25519signature verifies under the agent's public key (embedded in the bundle'sagents[]). - The bytes signed are exactly the bytes recorded. Tampering with any of
event_type,action,resource,input_hash,output_hash, orresultinvalidates the signature.
What verification does NOT prove
Be honest about the limits:
- It does not prove the agent's identity is who it claims to be. That requires a separate trust anchor (the Vorim trust API, an IdP, a public key directory). The verifier confirms the binding between the signature and the public key in the bundle.
- It does not prove the bundle is recent. Add a timestamp authority or an externally-witnessed hash chain if freshness matters.
- It does not detect missing events. A bundle with N signed events is a true record of those N events. Whether other events were dropped before export is outside the verifier's scope. Pair with the Vorim
audit_eventscount for that. unsignedandunknown_agentevents are reported but do not fail the bundle. Operator's call: a fresh bundle from a v3.1+ SDK should be 100% signed; an older bundle may not be. The CLI surfaces the count; the operator decides what the threshold is.
Bundle format
The verifier expects the JSON shape produced by POST /v1/audit/export on Vorim API (bundle_version: "vaip-v0"). Minimum required:
{
"bundle_version": "vaip-v0",
"events": [
{
"event_id": "evt_...",
"agent_id_str": "agid_...",
"event_type": "tool_call",
"action": "transfer_funds",
"resource": "acct-1",
"input_hash": null,
"output_hash": null,
"result": "success",
"signature": "ed25519:..."
}
],
"agents": [
{ "agent_id": "agid_...", "public_key": "-----BEGIN PUBLIC KEY-----\n..." }
],
"manifest": "sha256:..."
}Canonical bytes signed
event_type|action|resource|input_hash|output_hash|resultPipe-joined, empty string for missing optional fields. The verifier exposes canonicalPayloadV0() so you can reproduce the bytes yourself.
Programmatic use
import { verifyBundle } from '@vorim/verify';
const bundle = JSON.parse(fs.readFileSync('bundle.json', 'utf-8'));
const report = verifyBundle(bundle);
if (!report.ok) {
console.error('bundle failed verification', report);
process.exit(1);
}Returns a VerifyReport with per-event verdicts and aggregate counts.
Auditing this code
The verifier is small and intentionally has no runtime dependencies. To audit it from source:
git clone https://github.com/Vorim-AI-Labs/vorim-protocol
cd vorim-protocol/packages/verify
npm install
npm test # 23 unit tests
npm run build # produces dist/cli.jsRead src/index.ts for the verification logic (≈220 lines) and src/cli.ts for the CLI shim.
License
MIT — see LICENSE.
