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

76 lines
4.6 KiB
Markdown

# 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.