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.
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:
- Integrity of the
hostsfile. 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. - 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
hostsfile.
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.
-
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. -
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.comis covered byupdate.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. -
Reversible, with backups. A timestamped backup of the live
hostsfile 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). -
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 to0.0.0.0itself, 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 viaencode("idna"), and IP-like or multi-token values are rejected. Only syntactically valid single hostnames are ever written, each as exactly0.0.0.0 <domain>(plus:: <domain>with--ipv6). -
Atomic writes + least privilege. Writes go to a temp file in the same directory, are
fsync'd, thenos.replace'd over the target, so a crash mid-write can never leave a half-writtenhostsfile. 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 aPATH-resolved name, so the elevation prompt can't be hijacked by a planted binary.
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 TLS —
http://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.
-
tests/test_sinkhole.py— 37 self-running checks (no external tools, no realhostsfile 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
- 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
hostsfile 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
hostsfile linearly; hundreds of thousands of entries add lookup overhead. A hardMAX_DOMAINSguard (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.