2026-patterniha-mitm-domainfronting

MITM-DomainFronting: client-only domain fronting via local TLS MITM with a user-installed CA

Abstract

Persian-language GitHub project (1.5k stars, MIT/GPL-3.0) that implements **fully client-side domain fronting** without any server-side infrastructure. The project ships an Xray-core configuration plus a self-signed-CA bundle. Currently merged into Xray-core mainline (PR getlantern-style /XTLS/Xray-core/pull/4348), so any recent v2rayN / v2rayNG install can use the method via a single JSON config. **Mechanism, summarized in English (the README is in Persian):** 1. **Local CA install.** The user generates a personal root CA (`mycert.crt` / `mycert.key`) and installs the cert as a Trusted Root in their OS or in a specific browser. The private key never leaves the device. (The author repeatedly warns against accepting a CA from anyone else.) 2. **DNS hijack.** Xray's FakeDNS subsystem resolves the target domains (`google.com`, `vercel.com`, `reddit.com`, `github.com`, `pubmed.ncbi.nlm.nih.gov`, etc.) to local 127.0.0.1 sockets on port 11666 (HTTP/1.1) or 11777 (HTTP/2+HTTP/1.1). 3. **On-the-fly cert issuance.** Xray's `tunnel` inbound with `usage: "issue"` mints a leaf cert for whatever SNI the browser presents, signed by the user's personal CA. The browser's TLS handshake succeeds against the local proxy. 4. **Plaintext intercept.** The browser now sends its HTTP request in cleartext (relative to the local proxy). Xray reads the inner Host header and the request body. 5. **Re-encrypt with a fronted SNI.** Xray opens a new TLS connection to the destination CDN's real IP, but sets the outer SNI to a *different* domain on the same CDN — e.g. `nextjs.org` instead of `vercel.com`, `www.python.org` instead of `reddit.com`, `kubernetes.io` instead of any Netlify site, and `www.google.com` for any Google service. The inner Host header remains the user's true destination, so the CDN edge routes the request correctly. From the censor's perspective only the fronted SNI is visible. From the CDN's perspective the request is a normal incoming HTTPS request whose Host header it routes off of. From the browser's perspective it's a normal TLS connection to the real site (trusted via the installed personal CA). **Supported destinations (per the bundled config, as of 2026-05-14):** - Google services (Meet, Drive, Search, Maps, etc.) — fronted on `www.google.com`. (Gemini explicitly IP-blocks Iran, so excluded.) - Fastly-hosted sites — Reddit, GitHub, CNN, BuzzFeed, raw.githubusercontent.com, private-user-images.githubusercontent.com — fronted on `www.python.org`. - Vercel-hosted sites (Vercel.com, Next.js, React.dev, Cursor.com, Vercel.app, vercel.live, etc.) — fronted on `nextjs.org`. - Netlify (via Amazon CloudFront) — fronted on `kubernetes.io`. - GitHub.com / collector.github.com / alive.github.com / objects-origin.githubusercontent.com / api.githubcopilot.com — fronted on github.com itself (since github.com is allowed but the censor blocks specific subdomains). - pubmed.ncbi.nlm.nih.gov / pmc.ncbi.nlm.nih.gov — fronted on `pubmed.ncbi.nlm.nih.gov` (uses the same Akamai cert). - googlevideo.com (YouTube video chunks) — distinct h11-only path. **Limitations** (called out by the author): - Only works for traffic that can be MITM'd, i.e. browser traffic using the OS/browser cert store. Most native mobile apps use cert pinning and won't trust a user-installed CA. - On non-rooted Android, the user CA only applies to browsers (Chrome/Chromium-derived works out of the box; Firefox requires enabling "use third-party CA certificates" via the hidden debug menu). - This is **not a full VPN** — only the specific CDN-hosted endpoints above are reachable. Anything else still needs a real proxy. - Maintenance burden: the SNI ↔ destination pairing must be refreshed each time a CDN changes its cert SAN list or edge deployment. - Per-platform: Windows, Linux, macOS, Android (non-root). **Why it matters for circumvention research:** 1. **Empirical CDN behavior catalog.** The bundled config is an up-to-date catalog of which major CDNs as of 2026-05 *still* don't enforce SNI ↔ Host header matching. That's a moving target and this project's continual updates are useful telemetry. 2. **Client-only deployment model.** Unlike traditional domain fronting (which requires a server inside the fronted CDN's edge), this technique requires nothing beyond what the user can install locally. Lowers operational cost for anti-censorship tools. 3. **Iran-specific deployment data.** The author's commit cadence correlates with documented Iranian filtering changes; the project is essentially a moving snapshot of "what's reachable from Iran via CDN fronting" at any given week. **What's notable from a protocol-design standpoint:** - Forces the user into a trust trade-off (install our CA) for a consumer-grade circumvention tool. Most "easy + secure" tools avoid this; this project explicitly accepts the trade-off for the no-server property. - The fronted-SNI selection is hand-tuned per CDN by inspecting cert SAN lists — there's no automatic discovery. The `verifyPeerCertByName` field in each outbound is a whitelist of SANs the cert chain must include. - The technique can co-exist with a regular tunnel: only matching destinations are MITM'd; everything else falls through to the proxy. The shipped config uses `geosite:` and `domain:` route rules for this gating.

Team notes

Persian-language project (1.5k stars on GitHub, May 2026). README translated from Persian by Lantern team. Code lives in Xray-core mainline since PR XTLS/Xray-core#4348. License: GPL-3.0. Implementation: Batchfile + Xray-core JSON config. The on-the-fly cert issuance is a Xray-specific feature (`tunnel` inbound, `usage: "issue"`) — sing-box upstream does not have an equivalent primitive as of 2026-05, so a direct port to sing-box / lantern-box would require either patching sing-box or running a separate MITM component alongside it.

Tags

censors
irgeneric
techniques
sni-blockingdpidns-poisoning
defenses
domain-fronting