Verify our log yourself
Pin our public key, pull the signed checkpoints, and verify receipts offline. Trust nothing of ours.
AxioRank's audit log is a hosted RFC 6962 Merkle transparency log. You do not have to take our word that it is intact: pin our public key once, then verify every receipt and watch the log for tampering, all offline.
Independent verification means pinning the key out of band and checking against it. The convenience endpoints below are for tooling; your trust anchor is the pinned key plus the open-source verifier, never a live call to us.
1. Pin the public key
curl -s https://app.axiorank.com/api/v1/audit/public-key > jwks.jsonStore jwks.json somewhere you control. Every receipt and signed tree head verifies
against a key in this set, by its kid.
2. Verify a receipt offline
Download a receipt from the dashboard (Logs, Download receipt) or via the API
(GET /api/v1/audit/receipt/{auditLogId} with a logs:read key), then:
npx @axiorank/audit-verify receipt.json --jwks jwks.jsonimport { verifyReceipt } from "@axiorank/audit-verify";
import receipt from "./receipt.json";
import jwks from "./jwks.json";
const { ok, checks } = verifyReceipt(receipt, jwks);
// checks: leaf, inclusion, sthSignature, provenance, approverimport json
from axiorank import verify_receipt
receipt = json.load(open("receipt.json"))
jwks = json.load(open("jwks.json"))
print(verify_receipt(receipt, jwks)) # True only if every check passesA passing result proves the audit row is in a signed Merkle tree, the tree head was signed by the pinned key, the delegation provenance was signed, and (when a human approved a held call) the approver's own signature checks out. Tamper with any byte and it fails.
3. Watch the log over time
If you enable public monitoring (Settings, Security), your workspace gets an opaque log id. Run the open-source watchdog on a schedule to verify each new signed tree head and the chain between heads, and alert on any rollback or equivocation:
npx @axiorank/log-watchdog \
--base-url https://app.axiorank.com \
--log-id <your-log-id> \
--jwks ./jwks.json \
--state ./head.json \
--onceExit 0 means verified and pinned; exit 1 means tamper evidence. There is also a
GitHub Action (axiorank/log-watchdog) that caches the pinned head across runs and
opens an issue on any inconsistency. This is the "do not trust us, verify" half of
the platform: you continuously audit our log, including against us.
4. Independent witnessing (Sigstore Rekor)
Pinning protects you against a fork only from the moment you started watching. To close the gap, each sealed signed tree head is also submitted to Sigstore Rekor, a public append-only log operated by the Sigstore community, not by AxioRank. Rekor returns a Signed Entry Timestamp (SET) proving the head existed at that time, recorded in a log the whole ecosystem monitors. A rewritten history is then detectable by anyone, because the original head is permanently and independently timestamped.
Each checkpoint's witness records are returned in the witnesses array of the
public checkpoint endpoints. To require them, pin Rekor's public key and pass it to
the watchdog:
curl -s https://rekor.sigstore.dev/api/v1/log/publicKey > rekor-key.pem
# witnesses.json: [{ "keyId": "<rekor log id>", "publicKey": "<contents of rekor-key.pem>", "scheme": "rekor" }]
npx @axiorank/log-watchdog --log-id <id> --jwks jwks.json \
--require-witnesses 1 --witness-keys witnesses.json --onceThe verifier checks two things offline: that Rekor's SET signature is valid over the entry, and that the entry's artifact hash equals the head it claims to witness. The independence is Rekor's; the submission key is immaterial.
5. Run your own witness (Enterprise)
For the strongest independence, hold the witness key yourself. Run the
self-hostable @axiorank/log-witness
daemon on your own infrastructure and add its URL in Settings → Security →
Witnesses. AxioRank sends each sealed head to it and stores the
note:* countersignature alongside the checkpoint. Because the key is yours,
the attestation is independent of AxioRank by construction.
# generate a stable Ed25519 key once, keep it secret
node -e "const {generateKeyPairSync}=require('node:crypto');console.log(generateKeyPairSync('ed25519').privateKey.export({format:'der',type:'pkcs8'}).toString('base64'))"
AXR_WITNESS_NOTE_KEY="<base64>" AXR_WITNESS_NAME="note:acme" \
npx @axiorank/log-witness --port 8787Pin its public key (GET /key) and require the witness in the watchdog, exactly
as with Rekor but with "scheme": "note":
# witnesses.json: [{ "keyId": "<from GET /key>", "publicKey": <publicJwk from GET /key>, "scheme": "note" }]
npx @axiorank/log-watchdog --log-id <id> --jwks jwks.json \
--require-witnesses 1 --witness-keys witnesses.json --onceA signed-note witness is only as independent as the party holding its key, so run it where AxioRank cannot reach the private key.