Antivirus/crates/hound-defs/examples
Hound 13d86c167e houndd: fetch definitions from defs.houndav.com, and refuse anything unsigned
Closes Phase 3's delivery half. `hound update` now asks the definitions
host what exists, downloads what this machine lacks, verifies it, and
installs it. Verified end to end against the live host over TLS:

  starting from an empty directory:
    defs: no verified packs were found
  hound update:
    definitions: 1 pack(s) installed, 0 already current
    crates-io-2026.08.21.pack — 19 indicators, version 2026.08.21
    loaded 19 indicators from 1 pack(s) [2026.08.21]
  and immediately afterwards a lockfile naming rustdecimal is flagged,
  while tokio beside it is not.

  running it again:
    definitions: definitions are up to date (1 pack(s))

  a pack with one byte flipped in its signed payload, advertised in the
  index with a correct hash and a version of 9999.1.1:
    definitions: 0 pack(s) installed, 1 up to date, 1 REJECTED
    tampered-test.pack: the definitions pack is not signed by Hound and
    was discarded

Three refusals are the design:

* THE INDEX IS A HINT, NEVER AN AUTHORITY. It says which packs exist and
  what they hash to, and both are unverified — anyone who can serve the
  index can lie about either. Only the Ed25519 signature decides whether
  a pack is real. A tampered index can waste bandwidth and nothing else,
  which is exactly what the test above demonstrates: correct hash,
  higher version, still refused.

* NOTHING UNVERIFIED REACHES THE DEFINITIONS DIRECTORY. Downloaded to a
  temp file, verified there, then moved with a rename inside the same
  directory so it is atomic. The daemon cannot observe a half-written
  pack, and a crash mid-download leaves a stray temp file rather than a
  loadable one.

* A FILENAME FROM A REMOTE INDEX IS UNTRUSTED INPUT. The updater runs as
  root, so an entry of ../../../etc/cron.d/evil.pack would be remote code
  execution. Only a plain basename ending in .pack, with no separators,
  no dot-dot and no leading dot, is accepted. Tested against eight
  hostile shapes.

Sizes and timeouts are bounded — a pack is a list of package names, so a
server offering a hundred gigabytes is broken or hostile and the
difference does not matter to a full disk. The read is bounded
independently of Content-Length, which is also just something the server
said.

Definitions are fetched BEFORE rules are reloaded, and a failure to fetch
does not stop the reload. No network, a mirror down, a pack that will not
verify — none of those are a reason to skip the half that still works.

HOUNDD_DEFS_URL points the client at a mirror, which matters for the
air-gapped deployments that are a real part of the Fleet story.

build-pack now writes index.json beside the pack, so publishing is one
command.

358 tests pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 09:15:41 -05:00
..
build-pack.rs houndd: fetch definitions from defs.houndav.com, and refuse anything unsigned 2026-08-21 09:15:41 -05:00
ingest-osv.rs hound-defs: OSV ingest, the IOC index, and signed packs 2026-08-21 07:06:00 -05:00