feat(android): refuse plain http:// to a public server address (#5111)
release / go (push) Successful in 1m47s
release / govulncheck (push) Successful in 18s
release / web (push) Successful in 1m15s
release / integration (push) Successful in 4m44s
release / android (push) Successful in 5m37s
release / Build signed APK (releases and dev) (push) Successful in 5m43s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 1m13s
release / Verify release artifacts (tag releases only) (push) Skipped

Cleartext stays permitted app-wide for LAN servers and UPnP (#2439),
but a password or session cookie sent over plain HTTP to a public
address can be read by anyone on the path. A network interceptor now
refuses a cleartext request to the Minstrel server when the connection
lands on a public address, before any request byte is written.

Checked per connection, on the address actually reached, rather than
when the URL is typed: a name that resolved to the home network at
entry resolves to a public address once the phone leaves home.
Allowed: loopback, 10/8, 172.16/12, 192.168/16, link-local, 100.64/10
(Tailscale and other overlay VPNs) and fc00::/7. Only requests
BaseUrlInterceptor tagged as server-bound are checked; external
fetches and UPnP are untouched. The refusal has its own message.

Family baseline #5105, practice 13.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-06 23:02:07 -04:00
co-authored by Claude Opus 5.5
parent 40dd5bb52c
commit b28cbe0600
6 changed files with 194 additions and 3 deletions
@@ -17,8 +17,12 @@
hostnames rather than CIDR ranges, and both sets of hosts above are unknowable
until runtime. So a permissive base-config is an honest description of our
situation — the gain over the manifest attribute is that the reasoning now
lives somewhere, and there is one place to tighten if a future settings screen
can distinguish a LAN server from a WAN one.
lives somewhere.
The LAN/WAN line this file cannot draw is drawn in code instead:
api/CleartextGuard.kt refuses plain http:// to the Minstrel server whenever
the connection lands on a public address (family baseline #5105, practice
13). LAN servers and UPnP speakers are unaffected.
Worth stating because it looks worse than it is: this is NOT a tamper risk for
the in-app updater. An APK altered in transit and re-signed is rejected by the