Scanner signatures across the airgap
Holger's malware scanner is ClamAV, run as clamd in its own sandbox (no network, read-only root). On a box that never touches the internet, its signature database crosses the airgap the same way an intel bundle does: as a signed holger.update-bundle/v1, here with product = holger.scanner-sigs/v1 (lane HOL-NCSC; code in intel/src/sigs.rs, installed by server/lib/src/import_door.rs).
ONLINE │ AIRGAP │ SECURE
freshclam: main/daily/bytecode .cvd/.cld ─┐ │
a hotfix: hotfix-<id>.ndb ────────────────┼─ holger scanner-sigs build ─ USB ─ holger bundle import
YARA: rules.yar ──────────────────────────┘ (signed, two approvers) verify · floor · audit · install · clamd RELOAD
What a bundle may carry
Only signature files: payload/clamav/<name> with a ClamAV database extension (.cvd, .cld, .cud, .ndb, .hdb, .hsb, .ldb, .mdb, .fp, .sfp, .ign2, … the full list is holger_intel::sigs::CLAMAV_EXTENSIONS) and payload/yara/<name>.yar|.yara. A bare file name only: no path, no leading dot. The builder refuses anything else, and so does the import (holger-sigs-1, the whole bundle refused, nothing written).
The first set (online side, then the secure side)
On the online side, with freshclam's output in ./clamav and the site's release PKI:
holger scanner-sigs build --clamav-dir ./clamav --sequence 1 \
--policy trust-policy.ron --release-cert release.der --release-key release.pk8 \
--approve security-reviewer=reviewer.der,reviewer.pk8 --approve system-owner=owner.der,owner.pk8 \
--out sigs-1.holger.znippy
The trust policy names holger.scanner-sigs/v1 in allowed_products. On the secure side, the first bundle sets the anti-rollback floor, so an admin grants it once:
holger bundle allow-first-import --config holger.ron --from-bundle sigs-1.holger.znippy
holger bundle import --config holger.ron --bundle sigs-1.holger.znippy
holger scanner-sigs status --config holger.ron
The same import runs through every door: holger-cli bundle import, POST /-/bundle/import, gRPC AdminService.ImportBundle, and the <data_root>/bundle.inbox drop directory. The import verifies the release signature and the approvals, holds the sequence to the floor, writes its audit record first (scanner-sigs-import: bundle_id=… seq=… files=…), then moves the floor, then installs the files into <data_root>/sandbox/signatures/clamav/ and asks clamd to reload. From then on clamd reads that directory (mounted read-only over its DatabaseDirectory /var/lib/clamav) instead of the database its pinned image carried; a clamd started before the first bundle takes it at its next start.
A hotfix
A hotfix is one urgent signature, shipped before the next full refresh. It is the same kind of bundle with the next sequence and one file; it lands over the installed set and leaves every other file as it was.
- Online: write the signature, for example
hotfix-2026-10-31.ndb(Holger.Hotfix.Example:0:*:<hex>), check it withclamscan -d hotfix-2026-10-31.ndbon a sample, and put it alone in a directory. - Online:
holger scanner-sigs build --clamav-dir ./hotfix --sequence <installed + 1> …, approved and release-signed exactly like a full set (two people, the release key). - Carry it across. Secure side:
holger bundle import --config holger.ron --bundle sigs-<n>.holger.znippy(no new grant: the floor stands).holger scanner-sigs statuslists the hotfix file with its sequence.
A file is replaced by a later bundle that carries the same name (the next full refresh carries daily.cld again); an older bundle is a rollback and is refused, so a hotfix is never undone by replaying the set before it. Every refusal names its code, and the import door writes it into the audit log.
What is not here yet
- Withdrawing a single file: a later bundle can only add or replace files by name.
- YARA rules are carried and installed (
<data_root>/sandbox/signatures/yara/), but the scan worker does not read that directory yet. - The Kubernetes sidecar (
engine: remote) still uses the database of its image.