argand-site-registry/docs/SECURITY-REVIEW-0.4.md

4.6 KiB

Version 0.4 security review

Reviewed 2026-09-13 after implementation and before release promotion.

Scope and trust boundaries

The review covered source-manifest and acquisition validation, typed coverage, SQLite migrations and projections, observation import and candidate-site network access, reviewer votes and policy compilation, generation and revocation signing, consumer verification, CLI argument relationships, systemd isolation, dependency advisories, source packaging, and accidental credential or dataset disclosure.

The design treats provider bytes, websites, DNS answers, redirects, observation batches, public proposals, mirrors, and lookup results as untrusted. Reviewer and publisher private keys, the mutable writer database, consumer trust roots, and the host operating system remain privileged. A source assertion or observation cannot approve a route. One reviewer cannot satisfy the reference approval quorum, while one authenticated revocation can stop an exact subject.

Findings fixed before release

  1. Cross-generation revocation reinstatement: a publisher-signed feed could claim supersession while an older consumer lacked the reviewer votes needed to recompute it. Cross-generation feeds now only add blocks. Clearing a block requires the exact full generation containing the authenticated fresh quorum.
  2. Stale emergency feeds: feeds previously had no artifact deadline and a verified object could be reused indefinitely. Feeds now expire within seven days, and freshness is checked both during verification and every resolution.
  3. Resolver continuity: verify-revocations accepted a previous feed, while resolve had no equivalent input. resolve now accepts the last feed and signature and refuses replacements that discard subjects or vote IDs.
  4. Publisher/reviewer separation: physical-key and identity checks covered approval voters only. They now cover every reviewer vote, including emergency revocations, and remove a rejected signature output.
  5. Observation-batch mutation: completed batch counters, state, and membership were not all protected by schema triggers. A batch must now be created open, can complete once only with its exact row count, and cannot accept later rows, change, or be deleted.
  6. Policy-epoch revocation bypass: a new policy epoch retained an old signed revocation in the audit log but excluded it from compilation. All authenticated revocations now remain sticky across policy epochs until a fresh quorum under the active policy explicitly supersedes them.
  7. Special-address observation targets: the outbound filter omitted several IPv4 and IPv6 special-use ranges. The observer now also blocks IPv4-compatible, site-local, translation, discard, benchmarking, ORCHID, documentation, and 6to4 destinations before constructing a pinned client.

Regression coverage includes expired verified objects, signed cross-generation reinstatement attempts, physical reviewer-key reuse by a publisher, immutable observation batches and late inserts, policy-epoch revocation changes, signature and feed tampering, redirect loops, private and reserved address ranges, compressed bodies, malformed markup, extraction caps, and a deterministic 512-case parser mutation corpus.

Review result

No known critical, high, or medium security finding remains in the reviewed 0.4 scope. unsafe Rust is forbidden workspace-wide. External SSH operations use argument vectors and descriptor-bound private temporary files. Generation reads hash a no-follow source into a private unlinked SQLite snapshot before querying. Network clients disable ambient proxies; source acquisition uses reviewed HTTPS endpoints and explicit byte limits; the observer pins an entirely public DNS set per hop and bounds redirects, headers, body bytes, bandwidth, time, and extracted links.

cargo audit --deny warnings scanned 1,243 RustSec advisories across 272 locked dependencies without a finding. The complete offline gate separately exercises strict Clippy, documentation, unit and integration tests, native CLI behavior, consumer parity, source-package defenses, and the synthetic five-source import. systemd-analyze verify accepted the observer service and timer; its only output was an unrelated warning from the host's installed arch-audit.service.

This review authenticates software behavior, not provider truth or a public dataset. Publishers must protect writer and signing authority, inspect evidence, retain the last accepted feed, refresh it before expiry, and distribute trust roots through an independent authenticated channel.