checkId: check.evidencelocker.merkle plugin: stellaops.doctor.evidencelocker severity: fail tags: [evidence, merkle, anchoring, integrity]
Merkle Anchor Verification
This stella doctor check validates the Evidence Locker’s Merkle anchoring chain so operators can prove that stored evidence has not been tampered with and that anchoring is still running on schedule.
What It Checks
Verifies Merkle root anchoring integrity when anchoring is enabled. The check operates on anchor records stored in the anchors/ subdirectory of the evidence locker path. It validates:
- Anchor record presence: checks for
.jsonanchor files in the anchors directory. - Anchor structural validity: each anchor must contain
merkleRoot,timestamp,signature, and a verifiable leaf set (leafHashesorleaves) with non-empty values. - Anchor integrity: validates the most recent 5 anchor records by recomputing the Merkle root from the leaf hashes and comparing it to the declared
merkleRoot. - Anchor freshness: compares the latest anchor timestamp against the configured interval (
EvidenceLocker:Anchoring:IntervalHours, default 24). Warns if the latest anchor is more than 2x the interval age.
| Condition | Result |
|---|---|
| Anchoring not enabled | Skip |
| Evidence locker path not configured | Skip |
| No anchor records found | Warn |
| Any anchor records invalid (missing fields, missing leaf set, corrupt, root mismatch) | Fail |
| Latest anchor older than 2x configured interval | Warn |
| All checked anchors valid and fresh | Pass |
Evidence collected: CheckedCount, ValidCount, InvalidCount, InvalidAnchors, LatestAnchorTime, AnchorAgeHours, ExpectedIntervalHours, LatestRoot.
The check only runs when EvidenceLocker:Anchoring:Enabled is set to “true”.
Why It Matters
Merkle anchoring provides cryptographic proof that evidence has not been tampered with since the anchor was created. Each anchor captures the Merkle root hash of all evidence at a point in time, creating an immutable checkpoint. Invalid anchors mean the integrity chain is broken and evidence cannot be independently verified against its anchor. A legacy anchor that only carries a merkleRoot and signature but no leaf set is not treated as verified. Stale anchors indicate the anchoring job has stopped running, creating a window where evidence changes are not captured by any checkpoint.
Common Causes
- Anchoring job not run yet (new deployment)
- Anchoring job scheduler not running or misconfigured
- Anchor record corrupted on disk
- Merkle root hash mismatch due to evidence modification after anchoring
- Evidence tampered or modified after the anchor was created
- Anchors directory deleted during maintenance
- Anchor creation failing silently (check job logs)
How to Fix
Docker Compose
# Create an initial anchor
docker compose exec evidence-locker stella evidence anchor create
# Check anchor job status
docker compose exec evidence-locker stella evidence anchor status
# Audit anchor integrity
docker compose exec evidence-locker stella evidence anchor audit --full
# Verify a specific anchor
docker compose exec evidence-locker stella evidence anchor verify <anchor-filename>
# Enable anchoring in configuration
# EvidenceLocker__Anchoring__Enabled=true
# EvidenceLocker__Anchoring__IntervalHours=24
docker compose restart evidence-locker
Bare Metal / systemd
# Create an anchor
stella evidence anchor create
# Check anchor status
stella evidence anchor status
# Full anchor audit
stella evidence anchor audit --full
# Configure anchoring in appsettings.json
# "EvidenceLocker": {
# "Anchoring": {
# "Enabled": true,
# "IntervalHours": 24
# }
# }
# Verify the anchor job is scheduled
stella jobs list --filter anchor
sudo systemctl restart stellaops-evidence-locker
Kubernetes / Helm
# values.yaml
evidenceLocker:
anchoring:
enabled: true
intervalHours: 24
schedule: "0 0 * * *" # Daily at midnight (24h interval)
# Create initial anchor
kubectl exec deploy/stellaops-evidence-locker -- stella evidence anchor create
# Check anchor status
kubectl exec deploy/stellaops-evidence-locker -- stella evidence anchor status
# Audit anchors
kubectl exec deploy/stellaops-evidence-locker -- stella evidence anchor audit --full
helm upgrade stellaops ./charts/stellaops -f values.yaml
Verification
stella doctor run --check check.evidencelocker.merkle
Related Checks
check.evidencelocker.provenance— provenance chain integrity complements Merkle anchoringcheck.evidencelocker.index— index consistency ensures anchored artifacts are still presentcheck.evidencelocker.retrieval— retrieval health required to validate anchored artifactscheck.compliance.evidence-integrity— evidence integrity is the broader check that includes anchoring
