Skip to Content
Verifying Evidence

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:

ArtifactWhat it coversPlan tier
Signed exportTamper-evidence for a delivered compliance export packageProduction+
Checkpoint signatureTamper-evidence for an integrity checkpoint anchored outside Keel’s primary data pathProduction+
TSA receiptExternal timestamp witness for a checkpoint, where timestamping is enabledProvider set by plan (see section 5)

Each artifact can be verified independently. Verifying all three together provides the strongest audit posture, but each verification is meaningful on its own.


Action-access proof tiers

Action-access evidence is not a separate standalone artifact. It is classifier evidence embedded in a permit receipt, signed export, or checkpointed evidence chain. Interpret it by the artifact that carries it:

TierWhat is boundWhat verification proves
Signed bindingAction-access fields included in a signed permit-binding payloadThe included classifier facts match the signed binding payload.
ReceiptAction-access fields included in a permit receiptThe receipt carries those classifier facts and has not been altered under the receipt verification path.
Signed exportAction-access fields included in an export recordThe delivered export package still contains the same classifier facts Keel signed into that export.
TSA witnessA checkpoint/export window containing the action-access evidenceAn external timestamp witness issued a receipt for the covered checkpoint hash by the recorded time.

The evidence should include the classifier result, risk tags, source, confidence, registry version, registry hash, and classifier schema version when the runtime captured those fields. These tiers prove integrity of the recorded classifier evidence. They do not prove that the business decision was correct, that the action was semantically authorized, or that an unproxied direct API call did not happen outside Keel.


2. Required artifacts checklist

Before beginning, confirm you have the following:

For signed export verification:

  • The original JSON audit-export payload (e.g., export.json), extracted unchanged from a complete proof pack
  • The manifest, signed key manifest, independently trusted signing material, and every scope/checkpoint/other sidecar referenced by the selected proof pack

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.


Bulk exports are refused when the chain contains raw action arguments that fail the export privacy guard. See When a bulk export is refused.

3. Verify a signed export

What is being verified

A signed export has a payload and a JSON manifest. Authenticating its bytes also requires trusted signing material; structural claims can require additional sidecars. For the demonstrated offline chain/closure boundary, use a full_audit JSON proof pack with requested chain entries and preserve all extracted files. Record-only NDJSON/CSV downloads remain useful records, but do not by themselves establish that full offline boundary.

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 export.json manifest.json --key-manifest key_manifest.json --offline

Or with standard tools:

sha256sum export.json # compare output against manifest content_hash

Step 2 — Verify the Ed25519 signature.

The manifest’s signature field is an Ed25519 signature over its recorded content hash. Match the signer and its active window to independently trusted signing material, then verify the signature. The embedded public key alone does not establish Keel authenticity.

Using the Keel standalone verifier, Step 1 above performs both hash and signature verification in a single pass.

To verify manually, use an Ed25519 library and the independently trusted key. Preserved trusted material permits offline checking; a signature checked only against an artifact-supplied key establishes self-consistency.

Step 3 — Interpret the result.

  • Hash matches + signature valid under independently trusted Keel signing material → the export payload is unmodified since signing
  • 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 checkpoint establishes that the events it covers existed by its publication time, not at their own time.

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-key

The 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-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 checks that the receipt commits to the checkpoint hash. With --require-tsa-chain, keel-verifier 3.5.0+ also validates the release-pinned DigiCert/GlobalSign CMS signature, certificate chain, timestamping purpose, and bundled CRL snapshot at RFC 3161 genTime.

This strict mode is limited to the release-pinned trust bundle. It does not make a general OCSP, archival/LTV, legal, or court-admissibility claim.

Getting the TSA receipt

TSA receipts are embedded in the checkpoint JSON, not offered as a separate download: each entry in tsa_receipts carries the RFC 3161 token as base64 DER in receipt_b64 (the legacy tsa field holds the first one). Decode a receipt to a file for tools that expect DER, for example jq -r '.tsa_receipts[0].receipt_b64' checkpoint.json | base64 -d > receipt.der. The decoded receipt is standard RFC 3161 binary.

Where timestamping is enabled, Keel requests receipts from FreeTSA and DigiCert for Starter, and DigiCert and GlobalSign for Production and Enterprise. Each request is best effort, and tsa_attempts records failures. Starter checkpoint views show status only, with no receipt.

Steps

Step 1 — Confirm the receipt commits to the correct hash.

Using the Keel standalone verifier with the checkpoint that embeds the receipt:

keel-verify checkpoint <checkpoint-file> --require-tsa-chain

This confirms the receipt imprint and fails unless the TSA chain validates under the verifier’s release-pinned trust bundle. Run the same command without --require-tsa-chain when you need imprint verification but the receipt is not from that bundle.

Step 2 — Perform full CA-chain validation (optional, recommended for auditors).

openssl ts -verify \ -token_in \ -in receipt.der \ -digest <checkpoint-hash-hex> \ -sha256 \ -CAfile <tsa-ca-bundle.pem> \ -purpose timestampsign

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 -verify succeeds → 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/keys

Verification 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. Preserve independently trusted signing material and the retained rotation history needed for the artifact’s signing window.

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.

Operator migration warning

Keel operators upgrading from the legacy historical-key fallback must re-seed any retired public keys they still need into Keel’s rotation history. Once database-backed rotation history becomes authoritative, legacy fallback entries are shadowed rather than migrated automatically. If they are not re-seeded, older artifacts may no longer find those retired keys through the public manifest. Keel logs a warning when this condition occurs; verify the manifest still contains every retained verification key before completing an upgrade.

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 \ export.json manifest.json \ --key-manifest-url https://<your-keel-host>/v1/compliance/keys

The 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-file <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, a checkpoint that covers the exported window, and the TSA receipts embedded in that checkpoint where timestamping is enabled. Exported activity after the newest checkpoint has no covering checkpoint until a later one is published, so steps 2 and 3 do not apply to it.

Step 1 — Verify the export

Confirm the export payload has not been modified since Keel signed it.

keel-verify export \ export.json manifest.json \ --key-manifest key_manifest.json --offline

Expected outcome: the manifest’s recorded content_hash matches the payload and its Ed25519 signature validates under independently trusted signing material. Inspect each requested structural claim separately; successful payload authentication alone does not prove chain continuity or closure. See §3 Verify a signed export for full detail and the manual-tools alternative.

Plan tier: Production and Enterprise (signed exports are a Production+ 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.json \ --key-manifest-url https://api.keelapi.com/v1/compliance/keys

Expected 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: Production and Enterprise (externally anchored checkpoint artifacts are a Production+ 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.json \ --key-manifest-url https://api.keelapi.com/v1/compliance/keys \ --require-tsa-chain

For strict authenticity validation of a DigiCert/GlobalSign receipt, use --require-tsa-chain; it uses the verifier release’s pinned trust bundle and CRL snapshot. See §5 Verify a TSA receipt for the scope boundary.

Plan tier: where timestamping is enabled, Starter checkpoint views show status only, with no receipt; Production and Enterprise are shown DigiCert and GlobalSign receipts when present. Customer-selected timestamp authorities are not available on hosted Keel.

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/keys

The manifest lists every key Keel has retained, with purpose, valid_from, and valid_to per entry. Verify that:

  • the key_id resolved during steps 1 and 2 appears in the manifest under the appropriate purpose (export_signing or integrity_checkpoint);
  • each entry’s valid_from / valid_to window 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).
  • At least one external timestamp witness issued a receipt for the checkpoint hash by the receipt’s timestamp (Step 3, provider count depends on tier).
  • 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

VerificationWhat it establishes
Signed export — hash matchThe export payload is byte-for-byte identical to what Keel hashed at signing time
Signed export — signature validKeel’s signing key attested to this specific content hash
Checkpoint signature validKeel’s checkpoint key attested to this integrity state at the time of signing
TSA receipt — hash matchThe receipt is bound to this specific checkpoint hash
TSA receipt — authenticity validOpenSSL validated the CMS signature, configured trust-store chain, and timestamp-signing purpose for the receipt

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 -verify step 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 -text

Keel 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 (Production+)

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 Production+ 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

EndpointAuthScope
GET /v1/audit/integrityAdmin API keyProject bound to the API key
GET /v1/dashboard/projects/{project_id}/governance/integrityDashboard sessionCaller-owned project

Plan requirement

Production 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 Production plan or higher.", "required_plan": "production", "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.

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 checkpoint status is visible on every plan.

This route returns the most recent checkpoint.

The response always carries a visibility discriminator and a published_at timestamp (null when visibility is "empty"); the remaining fields are populated according to the caller’s plan.

Plan tiers

TiervisibilityWhat the response carries
Starterstatus_onlypublished_at of the most recent system-wide checkpoint. Artifact fields (checkpoint_id, chain_heads, external_anchor, tsa, tsa_receipts) are null.
Production (entitlement: external_checkpoint_artifact_enabled)full_envelopeAdds the project-scoped verification artifact plus DigiCert / GlobalSign RFC 3161 timestamp receipts in tsa_receipts and per-provider statuses in tsa_attempts when present.
Enterprisefull_envelopeSame as Production.

Checkpoint status (Starter)

{ "visibility": "status_only", "published_at": "2026-04-25T18:00:00Z", "checkpoint_id": null, "chain_heads": null, "external_anchor": null, "tsa": null }

published_at is when the most recent system-wide checkpoint was published. It shows whether checkpoints are current. It does not assert that the caller’s project chain head is in that specific checkpoint — that assertion is the verification artifact, which Production unlocks.

Verification artifact (Production)

{ "visibility": "full_envelope", "published_at": "2026-04-25T18:00:00Z", "checkpoint_id": "cp_abc123", "chain_heads": { "<project-uuid>": "head_hash..." }, "external_anchor": { "bucket": "customer-anchor-bucket", "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).

Timestamp witness receipts (Production / Enterprise)

Production and Enterprise responses can populate legacy tsa, tsa_receipts, and tsa_attempts. tsa remains the first receipt for compatibility; tsa_receipts carries the receipt list; tsa_attempts records per-provider success or failure. Verify receipts against the TSA CA bundle per section 5 when authenticity validation is required.

Empty state

When no checkpoint exists to describe, the route returns HTTP 200 with visibility: "empty" and every other field null, not 404. On Starter that means no checkpoint has been published yet. On Production and Enterprise it also covers a project whose chain head is not yet in the latest checkpoint.


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_integrity metadata 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, on a schedule. Governance history after the newest checkpoint is not covered by any checkpoint or checkpoint TSA receipt until a later checkpoint is published.

  • 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 explicit valid_from / valid_to windows per key, and the standalone verifier filters candidates by signing time to pick the correct key without operator pinning. The single-key endpoint GET /v1/integrity/checkpoint-public-key returns 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.


Last updated on Edit this page on GitHub