Verifying Keel Evidence
This page describes how to independently verify the cryptographic artifacts Keel produces. It is written for customers and auditors who want to confirm the integrity of delivered evidence without depending on Keel’s own claims.
Independent verification does not require access to Keel’s internal systems. The artifacts described here are self-contained or recoverable from documented public endpoints.
For the CISO-facing export verifier playbook, start with Independent Verification Overview, then run the workflow in Running Keel Verify. For failure-code triage, use the Tampering Detection Matrix.
1. Overview
Keel produces three categories of verifiable evidence:
| Artifact | What it covers | Plan tier |
|---|---|---|
| Signed export | Tamper-evidence for a delivered compliance export package | Business+ |
| Checkpoint signature | Tamper-evidence for an integrity checkpoint anchored outside Keel’s primary data path | Business+ |
| TSA receipt | Third-party timestamp witness for a checkpoint | Enterprise |
Each artifact can be verified independently. Verifying all three together provides the strongest audit posture, but each verification is meaningful on its own.
2. Required artifacts checklist
Before beginning, confirm you have the following:
For signed export verification:
- The compressed export payload file (e.g.,
export.jsonl.gz) - The manifest file accompanying the export (contains
content_hash,signature,public_key)
For checkpoint signature verification:
- The checkpoint record (hash value and metadata)
- The checkpoint signature
- The checkpoint signing public key (retrievable from the checkpoint public key endpoint)
For TSA receipt verification:
- The TSA receipt in DER format
- The checkpoint hash the receipt was issued against
- An RFC 3161-capable verification tool (e.g.,
openssl ts)
If any artifact is missing or cannot be retrieved, do not treat partial verification as full verification. Document what was and was not verifiable.
3. Verify a signed export
What is being verified
A signed export consists of two files: the compressed export payload and a JSON manifest. The manifest records the SHA-256 hash of the payload and an Ed25519 signature over that hash. Verifying the export confirms that the payload has not been modified since Keel signed it.
Steps
Step 1 — Recompute the payload hash.
Compute the SHA-256 of the compressed export payload. The result should match the content_hash field in the manifest (hex-encoded, prefixed sha256:).
Using the Keel standalone verifier:
keel-verify export --payload <export-file> --manifest <manifest-file>Or with standard tools:
sha256sum export.jsonl.gz
# compare output against manifest content_hashStep 2 — Verify the Ed25519 signature.
The manifest’s signature field is an Ed25519 signature over the content_hash value. Verify it using the public_key field in the manifest.
Using the Keel standalone verifier, Step 1 above performs both hash and signature verification in a single pass.
To verify manually, use any Ed25519 library. The manifest is self-contained: you do not need to call back to Keel to perform this verification.
Step 3 — Interpret the result.
- Hash matches + signature valid → the export payload is unmodified since Keel signed it
- Hash mismatch → the payload has been altered after signing; treat as tampered
- Signature invalid → the manifest has been altered, or the key in the manifest is not the key that signed this export; treat as tampered
What the manifest’s public_key field represents
The public_key embedded in each manifest is the key that was active when that export was signed. Exports signed under different keys each carry their own embedded public key. You do not need the currently active key to verify a historical export.
4. Verify a checkpoint signature
What a checkpoint is
A checkpoint is a signed snapshot of Keel’s integrity state — specifically a hash that represents the cumulative governance event chain up to that point. Checkpoints are published to external storage so that the integrity state exists outside Keel’s primary operational data path.
A valid checkpoint signature means that Keel attested to that integrity state at a specific point in time, and that the attestation has not been altered.
Retrieving the checkpoint signing public key
Keel exposes the current checkpoint signing public key at a dedicated public endpoint. Retrieve it before verification:
GET /v1/integrity/checkpoint/public-keyThe response contains the Ed25519 public key in a documented format. Store this key for use in Step 2 below.
Note: The checkpoint public key endpoint is unauthenticated and suitable for use in automated verification pipelines.
Steps
Step 1 — Obtain the checkpoint record.
Retrieve the checkpoint from your export package or from external storage if you have access to the anchored copy. The checkpoint record includes the checkpoint hash and associated metadata.
Step 2 — Verify the checkpoint signature.
Using the Keel standalone verifier:
keel-verify checkpoint --checkpoint <checkpoint-file> --public-key <public-key-file>Or verify manually using any Ed25519 library: confirm that the recorded signature over the checkpoint hash is valid under the retrieved public key.
Step 3 — Interpret the result.
- Signature valid → the checkpoint hash was produced by Keel and has not been altered since signing
- Signature invalid → the checkpoint has been altered or the wrong public key was used; do not rely on this checkpoint as evidence
5. Verify a TSA receipt
What TSA receipts are
RFC 3161 timestamp receipts are issued by an independent Time Stamping Authority (TSA). A receipt commits to a specific hash value and records that this hash existed at or before the time shown in the receipt, as witnessed by the TSA.
Keel issues TSA receipts against checkpoint hashes. A valid receipt means an independent third party witnessed that the checkpoint hash existed by the claimed timestamp.
TSA verification here checks that the receipt commits to the checkpoint hash. Full CA-chain validation can be performed with standard tools such as
openssl ts -verify.
Keel does not perform full CA-chain validation automatically. If your audit requires it, perform that validation yourself using the tools below.
Downloading the TSA receipt
TSA receipts are available for download in DER format from the compliance surface for your checkpoint. The receipt is standard RFC 3161 binary and is compatible with any compliant verification tool.
Steps
Step 1 — Confirm the receipt commits to the correct hash.
Using the Keel standalone verifier:
keel-verify tsa-receipt --receipt <receipt.der> --checkpoint-hash <hash>This confirms that the hash embedded in the receipt matches the checkpoint hash you are investigating.
Step 2 — Perform full CA-chain validation (optional, recommended for auditors).
openssl ts -verify \
-in receipt.der \
-digest <checkpoint-hash-hex> \
-CAfile <tsa-ca-bundle.pem>Supply the TSA’s CA certificate bundle as -CAfile. The TSA’s root certificate is typically published by the TSA itself. Keel does not supply the TSA’s CA bundle — obtain it directly from the TSA.
Step 3 — Interpret the result.
- Receipt hash matches checkpoint hash → the receipt is bound to this checkpoint
openssl ts -verifysucceeds → the receipt carries a valid timestamp signature from the TSA’s certificate chain- Mismatch or failure → do not treat this receipt as evidence for this checkpoint
6. Verifying with the key manifest
Signed exports and integrity checkpoints include an additive key_id field that identifies which signing key produced the artifact. The key manifest endpoint lists the verification public keys Keel has retained:
GET /v1/compliance/keysVerification tools that support the manifest can resolve the correct public key automatically, without requiring the caller to supply it explicitly.
Key states
Active keys sign new artifacts. Retired keys no longer sign new artifacts but remain in the manifest with their explicit activation and retirement timestamps so historical artifacts continue to verify. A retired key is not a compromised key.
Each manifest entry carries a valid_from / valid_to window that records when the key was active. Active keys carry an open-ended valid_to (null); retired keys carry the timestamp at which they were retired.
End-to-end rotation support
Signing-key rotation is end-to-end supported: past artifacts remain verifiable across rotation events because the public manifest emits explicit active windows per key, and the standalone verifier filters candidates by the artifact’s signing time. No operator action is required at verification time — the manifest carries the rotation history that the verifier needs.
The manifest is sourced from Keel’s internal rotation history. When a new key is activated, the prior key is retired with a precise timestamp and the manifest reflects the change automatically on the next request.
Migration note for self-hosted operators
Self-hosted deployments configured with a KEEL_HISTORIC_PUBLIC_KEYS environment variable retain that path as a cold-start fallback for deployments that have not yet populated the rotation history. Once the rotation history is populated (which happens automatically the first time a Keel instance boots after upgrading past migration 0146), the database becomes authoritative and environment-variable entries for the same purpose are shadowed.
This shadowing is intentional and not auto-migrated: previously-published retired keys configured via environment variables remain inert until an operator explicitly re-seeds them through Keel’s signing-key activation API. The migration model favors explicit operator action over silent database mutation on startup. A warning is logged when shadowing occurs so operators have a clear signal to re-seed any historical keys they want to keep manifest-visible.
Artifacts without key_id
Artifacts produced before key_id was introduced do not include that field. The standalone verifier can still verify them: when a legacy artifact carries a signing timestamp (signed_at for exports, computed_at for checkpoints), the verifier filters the manifest’s retained keys by each entry’s valid_from / valid_to window and selects the unique key that was active at signing time. This lets historical artifacts verify cleanly across past rotations without an embedded key_id. If multiple keys were simultaneously active during the rotation period (which should not occur with a properly-recorded rotation history), or the signing time falls outside every entry’s recorded window, verification fails with a clear error rather than guessing.
For artifacts that lack both key_id and a parseable signing timestamp, supply a public key explicitly with --expected-public-key.
Example: export verification using the manifest URL
keel-verify export \
--payload <export-file> \
--manifest <manifest-file> \
--key-manifest-url https://<your-keel-host>/v1/compliance/keysThe verifier reads the key_id from the export manifest and retrieves the corresponding public key from the manifest endpoint.
Example: checkpoint verification using a local manifest file
Download the manifest once and supply it as a local file to avoid a network call at verification time:
keel-verify checkpoint \
--checkpoint <checkpoint-file> \
--key-manifest <path-to-manifest.json>7. End-to-end verification recipe
When a customer or auditor needs to demonstrate full verification — for example, in response to a SOC 2 evidence request or a compliance review — run the four artifact-verification steps in sequence. Each step is independent; running all four together produces the strongest verifiable claim.
This recipe assumes you already hold a signed compliance export, the checkpoint that was active when the export was produced, and (on Enterprise) the TSA receipt that timestamped that checkpoint.
Step 1 — Verify the export
Confirm the export payload has not been modified since Keel signed it.
keel-verify export \
--payload export.jsonl.gz \
--manifest manifest.jsonExpected outcome: the manifest’s recorded content_hash matches the recomputed SHA-256 of the payload, and the Ed25519 signature validates under the manifest’s embedded public_key. See §3 Verify a signed export for full detail and the manual-tools alternative.
Plan tier: Business and above (signed exports are a Business+ artifact).
Step 2 — Verify the checkpoint
Confirm the checkpoint’s chain-head snapshot is consistent and that Keel’s checkpoint key signed it.
keel-verify checkpoint \
--checkpoint-file checkpoint.json \
--key-manifest-url https://api.keelapi.com/v1/compliance/keysExpected outcome: the composite_hash recomputed from chain_heads matches the checkpoint’s recorded hash, and the Ed25519 signature validates under the manifest entry that was active at signing time. See §4 Verify a checkpoint signature.
Plan tier: Business and above (externally anchored checkpoints are a Business+ artifact).
Step 3 — Verify the TSA receipt
Confirm an independent third party witnessed the checkpoint hash by the recorded timestamp.
The standalone verifier checks imprint correctness automatically when the checkpoint carries an embedded receipt:
keel-verify checkpoint \
--checkpoint-file checkpoint.json \
--key-manifest-url https://api.keelapi.com/v1/compliance/keysFor full CA-chain validation, run openssl ts -verify against the TSA’s CA bundle. See §5 Verify a TSA receipt for the full flow.
Plan tier: Enterprise (TSA receipts are an Enterprise-only artifact).
Step 4 — Reconcile against the public key manifest
Confirm that the keys used to verify the export and the checkpoint are present in Keel’s published rotation history with windows that cover the artifacts’ signing times.
curl -s https://api.keelapi.com/v1/compliance/keysThe manifest lists every key Keel has retained, with purpose, valid_from, and valid_to per entry. Verify that:
- the
key_idresolved during steps 1 and 2 appears in the manifest under the appropriatepurpose(export_signingorintegrity_checkpoint); - each entry’s
valid_from/valid_towindow covers the artifact’s signing time.
See §6 Verifying with the key manifest for rotation behavior, including legacy artifacts that lack an embedded key_id.
The manifest endpoint is unauthenticated and available on every plan; it serves verification needs across all tiers without requiring privileged access.
What end-to-end verification proves
- The export payload has not been modified since signing (Step 1).
- The checkpoint’s chain-head snapshot is consistent with Keel’s signature (Step 2).
- An independent TSA witnessed the checkpoint hash by the receipt’s timestamp (Step 3, Enterprise).
- The keys involved are part of Keel’s published rotation history with documented active windows (Step 4).
For the precise scope of what each step does and does not establish, see the next two sections.
8. What each verification proves
| Verification | What it establishes |
|---|---|
| Signed export — hash match | The export payload is byte-for-byte identical to what Keel hashed at signing time |
| Signed export — signature valid | Keel’s signing key attested to this specific content hash |
| Checkpoint signature valid | Keel’s checkpoint key attested to this integrity state at the time of signing |
| TSA receipt — hash match | The receipt is bound to this specific checkpoint hash |
| TSA receipt — CA-chain valid | An independent TSA witnessed this hash existed by the receipt’s recorded timestamp |
9. What each verification does NOT prove
This section is as important as the section above. Be precise when reporting on what was verified.
Signed exports do not prove:
- That the export is complete. The signature attests the content Keel packaged; it does not prove that all records that should be present are included.
- Per-record integrity. The signature covers the export as a unit, not individual records within it.
- That the chain integrity snapshot in the manifest covers every governance event ever written for the project. It reflects the chain state at export time.
Checkpoint signatures do not prove:
- That all records downstream of the checkpoint are included in a given export.
- That no records exist outside the checkpointed chain.
- That the checkpoint was published to external storage successfully — only that Keel signed it.
TSA receipts do not prove:
- Any business semantics: what decisions were made, what policies were in effect, or what an execution contained.
- That the underlying governance records are complete or accurate.
- That Keel’s internal systems were operating correctly at the timestamped time.
- CA-chain validity on their own — that requires the full
openssl ts -verifystep with the TSA’s CA bundle.
10. Troubleshooting
Hash mismatch on export verification
Likely cause: The export payload was modified after download (e.g., decompressed and re-compressed, or partially transferred). Re-download the export and verify the raw compressed file before any processing.
Signature invalid on export
Likely cause: The manifest file does not correspond to this export payload, or either file was modified. Confirm you are using the manifest that was delivered alongside this specific export. Check that the export_id in the manifest matches the export you requested.
Checkpoint public key endpoint returns a different key than expected
The checkpoint signing key has been rotated. Each checkpoint record embeds the key identifier used at signing time, and the key manifest at GET /v1/compliance/keys lists the rotation history with explicit valid_from / valid_to windows per key. The standalone verifier resolves the right key automatically when given the manifest — prefer --key-manifest (or --key-manifest-url) over relying on the single-key endpoint.
openssl ts -verify fails with certificate error
You are missing or using an incorrect CA bundle for the TSA. Obtain the correct CA bundle directly from the TSA named in the receipt. The issuer information is embedded in the receipt’s tsa_info field and can be extracted with:
openssl ts -reply -in receipt.der -textKeel standalone verifier not available
All three verification types can be performed with standard open-source tools (any Ed25519 library, openssl ts). The verifier is a convenience wrapper; it does not perform any verification that cannot be reproduced independently.
11. Programmatic chain verification (Growth+)
The verification flows in sections 3–6 cover artifacts a customer already holds (signed exports, checkpoints, TSA receipts) and require no privileged access to Keel. The integrity verification API is a complementary surface: it lets a Growth+ caller ask Keel to recompute the per-project hash chain in place and report whether the chain is intact.
This is a programmatic readback of the chain state Keel maintains. It does not replace verification of independently held artifacts — those remain the strongest form of independent verification — but it gives operations and audit teams a fast, automatable signal alongside the standalone verifier in section 4.
Endpoints
| Endpoint | Auth | Scope |
|---|---|---|
GET /v1/audit/integrity | Admin API key | Project bound to the API key |
GET /v1/dashboard/projects/{project_id}/governance/integrity | Dashboard session | Caller-owned project |
Plan requirement
Growth, Business, and Enterprise (entitlement: integrity_verification_api_enabled). Starter receives HTTP 403 with code plan.upgrade_required. The hash-chain itself is present on every plan; the gate is on the verification API, not on chain coverage.
Example — admin API key
curl -s https://api.keelapi.com/v1/audit/integrity \
-H "Authorization: Bearer $KEEL_ADMIN_API_KEY"Successful response:
{
"verified": true,
"records_checked": 12,
"digest_covered_records_checked": 4,
"chain_length": 12,
"last_verified_at": "2026-04-25T12:34:56Z",
"first_broken_at": null
}If the chain has been tampered with, verified is false and first_broken_at carries the event_id of the first broken link.
Below-tier response
A Starter-plan caller receives:
{
"error": {
"code": "plan.upgrade_required",
"message": "The integrity verification API requires the Growth plan or higher.",
"required_plan": "growth",
"current_plan": "starter",
"feature": "integrity_verification_api"
}
}What this proves
- The hash chain Keel maintains for the project is internally consistent at the moment of the call.
- Together with externally anchored checkpoints and the standalone verifier, an operator can correlate Keel’s reported chain state against an independently held checkpoint snapshot.
What this does not prove
- It is a Keel-side recomputation. A signed checkpoint (verified per section 4) anchored outside Keel’s primary data path remains the stronger evidence for tamper-resistance against simultaneous internal compromise.
- It does not establish per-record inclusion proofs.
- It does not validate signed exports or TSA receipts. Use the corresponding sections above for those artifacts.
Related
- Trust & Integrity — the four-layer model and where this API sits within it
- Multi-TSA Configuration — independent timestamp witness configuration on Enterprise
- Plans & Entitlements — full plan-tier entitlement matrix
12. Latest-checkpoint surface (visibility-tiered)
GET /v1/dashboard/projects/{project_id}/integrity/latest-checkpoint is the dashboard-session companion to the integrity verification API. It is reachable on every plan, but the response body is differentiated by tier so the verification artifact remains a paid surface while the trust-stack-alive signal is universal.
The response always carries a visibility discriminator and a published_at timestamp; the remaining fields are populated according to the caller’s plan.
Plan tiers
| Tier | visibility | What the response carries |
|---|---|---|
| Starter / Growth | status_only | published_at of the most recent system-wide checkpoint tick. Artifact fields (checkpoint_id, chain_heads, external_anchor, tsa) are null. |
Business (entitlement: external_checkpoint_artifact_enabled) | full_envelope | Adds the project-scoped verification artifact: checkpoint_id, chain_heads, and external_anchor (bucket, object_key, url). |
| Enterprise | full_envelope | Same as Business plus the embedded RFC 3161 tsa receipt (independent timestamp witness). |
Anchoring status (Starter / Growth)
{
"visibility": "status_only",
"published_at": "2026-04-25T18:00:00Z",
"checkpoint_id": null,
"chain_heads": null,
"external_anchor": null,
"tsa": null
}This is the trust signal that the checkpoint cron is running. It does not assert that the caller’s project chain head is in that specific checkpoint — that assertion is the verification artifact, which Business unlocks.
Verification artifact (Business)
{
"visibility": "full_envelope",
"published_at": "2026-04-25T18:00:00Z",
"checkpoint_id": "cp_abc123",
"chain_heads": { "<project-uuid>": "head_hash..." },
"external_anchor": {
"bucket": "keel-checkpoints",
"object_key": "checkpoints/2026/04/25/cp_abc123.json",
"url": "https://anchors.example.com/checkpoints/2026/04/25/cp_abc123.json"
},
"tsa": null
}Use the external_anchor.url to fetch the published checkpoint and verify it externally — the verification flow is the same as section 4 (standalone verifier) and section 5 (manual signature check).
Independent timestamp witness (Enterprise)
Enterprise responses additionally populate tsa with tsa_url, requested_at, receipt_hash, and receipt_b64. Verify the receipt against the TSA’s CA bundle per section 6.
404 semantics
Both visibility tiers return 404 not_found when no checkpoint exists to describe. For status_only that means no checkpoint events have been written yet (cold deploy, before the cron’s first tick). For full_envelope it additionally covers the case where checkpoints exist but none of them include this project’s chain head.
Related
- Trust & Integrity § External integrity checkpoints — where this surface sits in the four-layer model
- Plans & Entitlements — feature gating overview
13. Limitations
The following limitations apply to the verification methods described on this page:
-
Export completeness is not verifiable cryptographically. A signed export proves the payload is unmodified; it does not prove the payload is complete. Record-level inclusion proofs are not currently available.
-
Chain coverage is a snapshot. The
chain_integritymetadata in an export manifest reflects the chain length at export time. It does not prove that all governance events ever written for the project are represented. -
Checkpoint anchoring is not a real-time guarantee. Checkpoints are published to external storage asynchronously. A checkpoint that was signed but not yet published cannot be independently verified from external storage until publication completes.
-
TSA timing granularity is determined by the TSA. The timestamp in a receipt reflects the TSA’s clock and policies, not Keel’s. Sub-second timing claims should not be drawn from TSA receipts.
-
Key rotation is end-to-end supported. Exports and checkpoints remain verifiable across rotation events. The key manifest (
GET /v1/compliance/keys) emits the rotation history with explicitvalid_from/valid_towindows per key, and the standalone verifier filters candidates by signing time to pick the correct key without operator pinning. The single-key endpointGET /v1/integrity/checkpoint-public-keyreturns only the currently active key and is preserved for backwards compatibility — for verification across rotations, prefer the manifest endpoint. -
These verifications are independent of business logic. A successful cryptographic verification means the artifacts have not been altered. It does not constitute an audit opinion on the accuracy, completeness, or sufficiency of the underlying records for any specific compliance requirement.
Related pages
- Independent Verification Overview — what export verification proves and does not prove
- Running Keel Verify — step-by-step CISO verifier walkthrough
- Tampering Detection Matrix — audit meaning for verifier failure codes
- Key Rotation and Active Windows — how the public key manifest resolves old and new keys
- Trust & Integrity — the four-layer integrity model and its non-claims
- Signed Exports — requesting and structuring a signed export
- Multi-TSA Configuration — the default TSA configuration and the forward-looking additive multi-TSA model for Enterprise
- Route Guarantees — trust properties per public API route
- Security — the broader public security boundary
- Known Limits — documented boundaries of the current integrity stack