Skip to content

Commit 63a0080

Browse files
committed
stealth(leakage): static leakage checks, CI gates & release/QA policy
1 parent d665771 commit 63a0080

8 files changed

Lines changed: 2781 additions & 0 deletions

docs/stealth-builds.md

Lines changed: 344 additions & 0 deletions
Large diffs are not rendered by default.

docs/stealth-leakage-checks.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Stealth Leakage Checks
2+
3+
`scripts/stealth/check_leakage.py` scans built stealth artifacts for normal
4+
Lantern identifiers. It accepts APK, AAB, ZIP-like archives, and unpacked build
5+
directories. Archive entries are scanned recursively, and string matching checks
6+
UTF-8, UTF-16LE, and UTF-16BE encodings.
7+
8+
Run the default stealth check:
9+
10+
```sh
11+
make stealth-leakage-check \
12+
STEALTH_LEAKAGE_PATHS="path/to/app.apk path/to/app.aab"
13+
```
14+
15+
Run the stricter no-VPN variant:
16+
17+
```sh
18+
make stealth-novpn-leakage-check \
19+
STEALTH_LEAKAGE_PATHS="path/to/app.apk"
20+
```
21+
22+
If the configured targets are absent, the Make targets skip successfully. This
23+
keeps normal builds and ordinary CI runs from failing on stealth-only checks.
24+
25+
## Modes
26+
27+
The forbidden-token config lives at
28+
`scripts/stealth/forbidden_tokens.json`.
29+
30+
### `stealth` (base)
31+
32+
Checks for normal Lantern package, brand, library, service, and organization
33+
identifiers; user-facing VPN strings; OAuth provider strings and method-channel
34+
entry points; billing and subscription entry points; app-link hosts, custom
35+
schemes, and deep-link paths; Lantern social/support URLs; and update feed and
36+
release URLs.
37+
38+
### `stealth-vpn`
39+
40+
Brand-only policy for the de-branded full-featured VPN variant. Checks the
41+
`lantern_identity` and `social_urls` categories only. Generic tokens such as
42+
`oauth`, `stripe`, `billing`, and `VPN` are intentionally allowed — login,
43+
payment, and VPN surfaces are retained in this variant. OAuth2 and the
44+
`lantern://` deep-link scheme are excluded at source (via `//go:build !stealth`
45+
build tags in `account/oauth.go`, `backend/oauth.go`, and `mobile_oauth.go`),
46+
so they are absent from the binary for the correct reason — not merely
47+
garble-encrypted. The `lantern_identity` tokens are case-insensitive substrings
48+
that catch all brand variants (`lantern.io`, `lantern://`, `org.getlantern.*`,
49+
etc.) without false positives on generic tokens.
50+
51+
### `stealth-novpn`
52+
53+
Scans the same brand-only token set as `stealth-vpn` (`lantern_identity` +
54+
`social_urls`), with an empty allowlist.
55+
56+
VPN/TUN surfaces are **not** enforced by token scanning here. Native gomobile
57+
JNI class-name strings (e.g. `OverrideAndroidVPN`, `TunOptions`) cannot be
58+
scrubbed or scanned without breaking `FindClass` lookups at runtime. Instead,
59+
no-VPN VPN/TUN removal is **structural**: the Go `novpn` build tag excludes the
60+
tunnel code, and the no-VPN manifest declares no `VpnService`/`BIND_VPN_SERVICE`
61+
— verified by the manifest-diff tests, not by this leakage gate.
62+
63+
## Scanner limitations
64+
65+
`check_leakage` and raw `strings | grep` scan the post-garble binary. When a
66+
Go package is in `GARBLE_GOGARBLE` scope, garble `-literals` encrypts string
67+
literals at compile time, so brand strings in compiled-in garble packages are
68+
absent from the static binary but present at runtime. A pass from
69+
`check_leakage` alone is not sufficient evidence of brand removal for garbled
70+
packages.
71+
72+
See `docs/stealth-builds.md` ("Garble string-literal obfuscation blind spot"
73+
and "Standing nm -D brand-symbol gate") for the required complementary checks.
74+
75+
## Allowlists
76+
77+
Each mode supports an `allowlist` in the JSON config. Allowlist entries can
78+
match by `token`, `category`, `location` glob, and `encoding`. Example:
79+
80+
```json
81+
{
82+
"token": "Lantern",
83+
"location": "*.SF",
84+
"reason": "example only"
85+
}
86+
```
87+
88+
Keep allowlist entries narrow and mode-specific so real leaks still fail the
89+
scan.

0 commit comments

Comments
 (0)