Skip to content

Security: strix-tool/strix-sinkhole

SECURITY.md

Security Policy — Strix Sinkhole

Reporting a vulnerability

Please do not open a public issue for security problems. Report privately via GitHub Security Advisories ("Report a vulnerability" on the repo's Security tab), or contact the maintainers listed on the Strix Advanced Tools organization. We aim to acknowledge within 72 hours.

Threat model

Strix Sinkhole edits the system hosts file — a high-value, security-sensitive file that is also a classic malware target. Two things therefore drive the whole design:

  1. Integrity of the hosts file. A bug (or a crash mid-write) must never corrupt the file, clobber the user's own entries, or leave the machine unable to reach the network. Every change must be recoverable.
  2. The blocklist is untrusted input. Whether it is the bundled seed, a file you import, or a list fetched over HTTPS, its contents are attacker-influenced: an over-broad or hostile list must not be able to blackhole critical infrastructure or smuggle arbitrary data into your hosts file.

Strix Sinkhole is otherwise a local, offline tool. It spawns no shell, uses no dynamic code (eval / exec / pickle / marshal / yaml), and makes no network calls of its own — the only outbound request is the explicitly opt-in, consent-gated list updater described below.

Hardening — the five guarantees

  1. Namespaced managed block (your entries are never touched). Everything Strix writes lives between two markers:

    # >>> STRIX SINKHOLE (managed) - do not edit by hand >>>
    …
    # <<< STRIX SINKHOLE (managed) <<<
    

    The build step (build_hosts) only ever removes/replaces this marked block and copies the entire rest of the file — your custom entries and the system defaults (localhost, ::1, broadcasthost, …) — byte-for-byte. Before any write, assert_preserves_user() compares the non-managed section before and after and the tool refuses to write if it would change. This invariant is proven by the test suite.

  2. A critical-domain guard that can't be overridden. A curated, deliberately small set of critical hosts — OS/security update (Windows Update, Ubuntu/Debian/ Kali/Apple mirrors), certificate revocation / OCSP & CRL endpoints (blackholing these breaks TLS), time synchronisation (clock skew breaks TLS and auth), and the loopback/local names — is refused from every blocklist, matched by exact host or parent domain (so sls.update.microsoft.com is covered by update.microsoft.com). No imported or fetched list can blackhole them, so a hostile or over-broad list cannot silently break your machine, your updates, or your bank's certificate checks.

  3. Reversible, with backups. A timestamped backup of the live hosts file is written before every change (make_backup), disable removes the Strix block and restores the exact original user section, and restore rolls back to the latest backup (taking a fresh backup of the current state first, as a safety net).

  4. No injection. Blocklist parsing takes only the hostname from a line; the IP in a hosts-format line (0.0.0.0 …, 127.0.0.1 …) is discarded — Strix always null-routes to 0.0.0.0 itself, so a line can never smuggle a real IP into your file. Each candidate is validated (normalize_domain) against a bounded RFC-1123 hostname regex (no catastrophic backtracking on a hostile blob), IDNs are normalised via encode("idna"), and IP-like or multi-token values are rejected. Only syntactically valid single hostnames are ever written, each as exactly 0.0.0.0 <domain> (plus :: <domain> with --ipv6).

  5. Atomic writes + least privilege. Writes go to a temp file in the same directory, are fsync'd, then os.replace'd over the target, so a crash mid-write can never leave a half-written hosts file. The tool needs Administrator/root only to write the file; it reads status and previews changes read-only otherwise. On Windows the GUI offers an elevated relaunch via the absolute interpreter path (sys.executable), never a PATH-resolved name, so the elevation prompt can't be hijacked by a planted binary.

The opt-in list updater

The only network feature is update <https-url> (CLI) / Update from URL (GUI). It is:

  • Consent-gated — the pure core never fetches on its own; a caller must invoke fetch_list() only after asking the user, and the CLI/GUI both prompt first.
  • HTTPS-only, with verified TLShttp:// is refused; the request uses a default verifying SSL context.
  • Bounded — a connection timeout and an 8 MiB read cap so a hostile or broken server can't stream forever or exhaust memory.

Whatever is fetched still passes through the same parsing, validation, critical-domain guard, and assert_preserves_user check as any other list.

Verification

  • tests/test_sinkhole.py37 self-running checks (no external tools, no real hosts file touched): hostname normalisation/rejection, blocklist parsing, the critical-domain guard end-to-end, user-section preservation, idempotent enable + fully reversible disable, the no-injection invariant (attacker IP never copied; every managed line null-routes a single host), diff correctness, and the large-list guard. Run:

    python tests/test_sinkhole.py

Known limitations

  • Hosts-level blocking only — this is not encrypted DNS. Strix stops lookups for domains on the list, on your machine. It does not encrypt or protect your DNS traffic upstream, so it is not a defence against on-path or ISP DNS snooping of the queries it doesn't block. Pair it with DNS-over-HTTPS/TLS if that is your threat model.
  • Unsigned Windows build may trip SmartScreen / AV. Editing the hosts file is a known malware technique, so an unsigned build can be flagged on first run. This is expected; verify the source and choose More info → Run anyway.
  • A very large imported list can slow name resolution. The OS reads the hosts file linearly; hundreds of thousands of entries add lookup overhead. A hard MAX_DOMAINS guard (500,000) refuses absurd lists, but for everyday use a modest, curated list is faster and easier to audit.
  • Blocking is by exact domain. Trackers that rotate to fresh domains, or that are served from the same host as content you want, are not caught by a static list — keep your lists updated and use the allowlist for false positives.

There aren't any published security advisories