The backup that notices you're being encrypted.
BETARansomware’s tell is physical: turning plaintext into ciphertext raises its entropy toward the 8 bits/byte ceiling and collapses how well it compresses or dedupes. A backup system measures both on every run — so TillArk can alarm on an encryption-in-progress before it finishes. Nobody offers this natively; we can, because we’re already reading every byte.
Two measurements, moving together
Neither signal is proof on its own — some sources are legitimately high-entropy (media, already- compressed blobs). It’s the two together, measured against this source’s own recent history, that is the encryption signature.
A normal database backup An encrypted (ransomware) backup
────────────────────────────── ──────────────────────────────
entropy ~4–6 bits/byte (structured) entropy ~7.9 bits/byte (ciphertext)
dedup 2–4× (compresses) dedup ~1.0× (incompressible)
│ │
└ within this source's baseline └ SPIKE + COLLAPSE, together
└▶ canary fires: ALARMSigned on the way out, judged on the way in
The agent measures Shannon entropy as it streams the backup to storage — a 256-bucket histogram on an io.TeeReader, so nothing is buffered. The value is signed into the manifest next to the dedup ratio, so it is tamper-evident at rest and re-checkable at restore — someone who alters a stored backup can’t rewrite its entropy without breaking the signature. The control plane re-verifies that signature at report time against the reporting agent’s registered key, then judges the signed reading against the source baseline — so the verdict is never based on an unauthenticated number.
agent backup ──▶ streams bytes to object storage
│ (never buffered through the control plane)
└─ io.TeeReader tap ─▶ 256-bucket histogram ─▶ Shannon entropy (bits/byte)
│
signed into the manifest ◀──────────────────────────┘ (tamper-evident:
(entropy_bpb_milli, alongside dedup_ratio) lowering it breaks
│ the signature)
▼
control plane compares the new (entropy, dedup) against the source's
rolling baseline of recent healthy backups → verdict: normal | watch | alarmWatch, alarm, and why
Every judgement carries machine-readable reason codes and the evidence (the sample versus the baseline), so triage is a fact, not a guess.
| Verdict | When | Severity |
|---|---|---|
| alarm | Rising/high entropy AND a dedup collapse together — the encryption signature. | critical |
| watch | A single strong signal (an entropy spike, or a compression collapse) but not both. | high / medium |
| normal | Within baseline — the silent, common case (not recorded). | — |
Reason codes include combined_encryption_signature, entropy_spike, entropy_absolute_high, and dedup_collapse. The decision logic is a pure, unit-tested function in @tilldev/ark-core — no clock, no network — so it’s fully replayable.
Observability-native, on the Recovery Board
Because TillArk reports to TillPulse, a canary event isn’t a side-channel — it’s an entropy sentinel on your Recovery Board: a per-source entropy meter-bridge and the live signals, with acknowledge / false-positive triage. An open alarm flips the whole instrument to signal-red. Every alarm, quarantine and acknowledgement appends to the tillark_audit trail (canary.alarm / canary.quarantine / canary.ack).
See Security & verification for the signed-manifest model the canary rides on, or the PII-scrubbed clones the same byte-level view makes possible. Back to the TillArk overview.