Verifying EVE Artifact Scan Evidence
Artifact scan evidence (eve.artifact_scan.evidence.v1) is a signed record of ingesting a
file, detecting its real media type from content, applying bounded safe-parsing limits, running
deterministic scanners, and deciding to allow, block, quarantine, redact, or require approval —
with the artifact digest bound to the decision. The evidence lets a reviewer confirm the
scan result is authentic and that a substituted file would be detected — without trusting the
EVE server.
Readiness: deterministic multimodal artifact scanning + signed evidence and artifact
substitution protection are PILOT_READY (customer-pilot ready at supported boundaries).
What it proves
- Integrity + authenticity — the scan result (findings, final action, completeness) was
signed by the EVE signing key (Ed25519 in the production configuration; HMAC-SHA256 fallback
is symmetric and not independently verifiable) over
jcs-1canonical bytes. - Substitution protection — the evidence binds the
artifact_digest. If the file is swapped for a different one after approval, verification of the evidence against the new file's digest fails. Verification rejects an evidence whoseartifact_digestwas changed. - Deterministic derivation — the shipped scanners are deterministic (pattern / structure based); the recorded media type was detected from content (magic-byte / structural), and the declared type is only compared, never trusted.
- Completeness honesty — incomplete extraction is reported as partial and cannot masquerade as complete; the completeness status is signature-covered.
What it does NOT prove
- It does not claim complete understanding of every artifact. OCR, vision, and QR/barcode
decoding are probabilistic, disabled by default, and recorded as
unavailable. A clean scan under default settings is a deterministic-scanner result, not a full-content understanding. - It does not by itself enforce re-scan-before-use. Substitution is detected at verification time; wiring a re-scan at the ingestion boundary is a per-deployment responsibility. If your integration does not verify before use, a swap is not caught.
- It does not attest that a permitted file is safe in an absolute sense — deterministic detectors are pattern-based and a novel obfuscation may evade them until a detector is added (findings are versioned, so coverage changes are auditable).
Required keys
eve.artifact_scan.evidence.v1 binds at least:
| Field | Meaning |
|---|---|
| schema version | eve.artifact_scan.evidence.v1 identifier |
artifact_digest |
SHA-256 of the ingested artifact (substitution binding) |
| descriptor | Content-based ArtifactDescriptor (detected vs declared media type) |
| parser / scanner / policy versions | Versioned components |
findings_digest |
Digest of the full findings set |
| extraction-status digest | Digest of what was / was not extracted |
| completeness status | complete / partial (fail-closed on incomplete) |
final_action |
BLOCK / QUARANTINE / REQUIRE_APPROVAL / REDACT / ALLOW_WITH_FINDINGS / ALLOW / UNSUPPORTED |
| CoreGuard decision | The bound governance decision |
| tenant / principal / workflow / session / destination / tool | Context |
| prev / current hash | Evidence-chain links |
kid, canon, signature |
Signer key, jcs-1, signature |
Verification fails closed if a required key is absent.
Canonicalization (jcs-1)
Evidence is signed over jcs-1, a constrained RFC 8785 profile with proven byte-for-byte
parity across Python, TypeScript, and the browser for the supported value domain. jcs-1 fails
closed on non-integer floats / NaN / Infinity. A verifier reading evidence whose canon is not
jcs-1 reports unsupported canonicalization.
Verification profiles: strict vs standard
- Standard — verifies canonicalization, content hash, signature, schema, and that the
artifact_digestmatches the file you hold. - Strict — additionally requires an independently verifiable Ed25519 signature and rejects
HMAC-fallback evidence. Use strict for external audit. The Node verifier for scan evidence is
verify_scan_evidence.mjs; the Python path isverify_scan_evidence/verify_evidence.
Linked evidence
- Decision Certificate — the CoreGuard decision bound to the scan.
- MCP Execution Evidence — if the artifact was a tool-argument file, the approved-versus-executed binding for the tool call.
- Red Team Report — adversarial artifact cases (credential / exfil / traversal / bomb / polyglot) and multi-step chains that start with a poisoned document.
Verify each linked artifact independently.
Selective-disclosure / omission checks
The signature covers the whole canonical payload; the findings_digest binds the full
findings set, so dropping a finding is detected. Removing or altering the completeness status,
the descriptor, or the artifact_digest invalidates the content hash and the signature. Verify
the full evidence before reading a subset; do not re-canonicalize a reduced object.
Failure categories
| Category | Meaning |
|---|---|
| invalid signature | Signature does not match the canonical content under the given key |
| unknown key | kid / public key not recognized or not supplied for a strict check |
| unsupported schema | Evidence schema version is not understood by this verifier |
| unsupported canonicalization | canon is not jcs-1 |
| digest mismatch | artifact_digest != the file you hold, or content_hash mismatch |
| selective omission | A signature-covered finding or field was removed / altered |
| stale | Evidence is older than your freshness window |
Note: unsupported artifact formats are surfaced as ARTIFACT_UNSUPPORTED_FORMAT (fail closed),
and archive hazards fail closed with explicit reasons (e.g. ARCHIVE_PATH_TRAVERSAL,
ARCHIVE_DECOMPRESSION_BOMB) — these are recorded in the evidence, not hidden.
Freshness
Scan evidence records a past scan under specific scanner and policy versions. It does not expire
on its own; enforce a freshness policy so you do not accept a scan produced under an outdated
scanner or policy version, and treat over-age evidence as stale. Because the scan cache is
keyed by (tenant, sha256, scanner_version, policy_version), a bump in scanner or policy
version means a fresh scan is warranted.
Replay behavior
Scan evidence is a record, not an authorization. Re-presenting it does not re-ingest a file and causes no side effect. A cache entry for one tenant never satisfies another tenant. To rely on a prior clean result, verify the evidence against the exact file digest you are about to use — this is what makes substitution detectable.
Verify it yourself
Python
# Verify the signature, then bind the result to the file you hold by comparing the
# signed artifact_digest against a local recompute. Synthetic fixture — no creds.
import hashlib, json
from core.eve_sdk import verify_evidence # ships with the EVE service
with open("scan_evidence.json", "r", encoding="utf-8") as fh:
evidence = json.load(fh)
# verify_evidence's first argument is the evidence KIND ("scan").
result = verify_evidence("scan", evidence, expected_tenant="org_abc")
assert result["valid"], result["reason"]
# Substitution check: recompute the local digest and compare to the signed field.
local_digest = hashlib.sha256(open("attachment.bin", "rb").read()).hexdigest()
signed_digest = evidence.get("artifact_digest", "").removeprefix("sha256:")
assert local_digest == signed_digest, "artifact substituted — digest mismatch"
print(result["valid"], result["reason"]) # True, "verified"
Node (TypeScript / ESM, Node >= 18)
import { verifyEvidence } from "@eve/coreguard";
import { readFileSync } from "node:fs";
import { createHash } from "node:crypto";
const publicKeyPem = readFileSync("public_key.pem", "utf8");
const evidence = JSON.parse(readFileSync("scan_evidence.json", "utf8"));
// 1) Verify content hash + Ed25519 signature.
const result = verifyEvidence(evidence, { publicKeyPem });
if (!result.valid) throw new Error(result.reason);
// 2) Substitution check: recompute the local digest and compare to the signed field.
const localDigest = createHash("sha256").update(readFileSync("attachment.bin")).digest("hex");
const signedDigest = String(evidence.artifact_digest ?? "").replace(/^sha256:/, "");
if (localDigest !== signedDigest) throw new Error("artifact substituted — digest mismatch");
console.log(result.valid, result.signature); // true "ed25519-valid"
CLI
# The `eve` CLI ships with the EVE service/repo. Form: verify <kind> <evidence.json>
# [--strict]; verify the signature here, then compare the signed artifact_digest to
# `sha256sum attachment.bin` to catch a substituted file.
python -m core.eve_sdk.cli verify scan scan_evidence.json --strict
Readiness
- Deterministic artifact scanning + signed evidence and artifact substitution
protection are
PILOT_READY(customer-pilot ready at supported boundaries). - Offline verification (Python / Node / browser for the evidence) is
SUPPORTED;jcs-1isSUPPORTED(constrained RFC 8785 profile). - Scanning runs in embedded (service) / sidecar mode; the Python
eve-coreguardclient (0.2.2) reaches the service via hosted mode. TypeScript verifies scan evidence offline and never signs. - Independent verification requires the Ed25519 public key; the HMAC fallback is symmetric and not independently verifiable.
- The release-candidate clients are distributed privately for pilots — install the pilot artifact, not a public
pip/npminstall (see readiness for public-registry status).
Limitations
- Deterministic scanners are pattern / structure based. OCR, vision, and QR/barcode are probabilistic and disabled by default (recorded as unavailable); incomplete extraction is reported as partial and cannot masquerade as complete.
- Substitution is detected at verification time; enforcing re-scan-before-use at the ingestion boundary is a per-deployment wiring responsibility.
- Novel obfuscations may evade pattern-based detectors until a detector is added; findings are versioned so coverage changes are auditable.
- In the pilot, the scan cache is in-process (bounded, tenant-partitioned); durability is a deployment concern.
- HMAC-fallback signatures are not independently verifiable; use the Ed25519 configuration and the strict profile for external audit.