Domain Fronting
Malware hides the true C2 destination behind a high-reputation CDN by putting an innocuous domain in the TLS SNI while the encrypted HTTP Host header points to the real backend.
Domain fronting exploits the gap between the domain a network observer sees and the domain a shared frontend actually routes to. When a client connects to a large CDN, the TLS handshake exposes the requested hostname in the cleartext Server Name Indication (SNI) field — but the HTTP Host header, sent inside the encrypted session, is what the CDN uses to pick the backend. By placing a benign, high-reputation domain in the SNI (one a defender is unlikely to block) and the real C2 domain in the Host header, malware makes its traffic appear destined for a trusted service.
The technique requires that both the decoy and the real backend be served by the same fronting infrastructure (historically Google, Amazon CloudFront, Azure, Fastly). APT29 famously fronted Tor's meek transport through trusted CDNs; Cobalt Strike supports it via its Host header malleable profile option. Major providers have since restricted same-CDN fronting, pushing actors toward the related "domainless"/SNI-omission and "CDN fronting" variants — but the analyst signature is the same.
How it works
The implant opens a normal HTTPS connection whose handshake names a decoy domain, then sends an inner request addressed to the real C2:
# TLS handshake (visible on the wire):
ClientHello SNI = allowed-cdn-frontend.example <- what the IDS/proxy sees
# HTTP request (encrypted inside the TLS session):
GET /beacon HTTP/1.1
Host: real-c2-backend.example <- what the CDN routes to
User-Agent: Mozilla/5.0 ...In code the pattern is a TLS client where the connect/SNI target and the Host header are deliberately different — often the SNI is hard-coded to a popular domain while the C2 hostname is supplied separately:
// Descriptive only: the SNI and Host intentionally diverge.
tls = tls_connect("allowed-cdn-frontend.example", 443); // sets SNI
http_set_header(req, "Host", "real-c2-backend.example"); // CDN backend selector
http_send(tls, req);For a reverser the tell is configuration (or a malleable profile) that specifies a Host value distinct from the connection target, plus pinning to a CDN IP range.
Detection & analysis
Static analysis:
- Recover the embedded TLS/HTTP configuration: a hard-coded SNI/hostname that differs from the
Hostheader string, or a Cobalt Strike profile blob, exposes the fronting setup. The decoy domain and the real backend are usually both present as strings. - Identify the CDN by resolving the decoy domain — a beacon "talking to Google/CloudFront" whose backend string is an unrelated domain is the giveaway.
- Confirm both domains share the same fronting infrastructure: if the decoy SNI and the
Hostbackend resolve into the same CDN address space, the front is viable and the pairing is deliberate rather than a benign redirect.
Dynamic analysis:
- Capture TLS and compare the ClientHello SNI against the decrypted (or proxy-logged)
Hostheader. A mismatch between SNI and Host for the same flow is the canonical indicator of fronting. - Fingerprint the client with JA3/JA3S. Malware TLS stacks (and Cobalt Strike's) often produce a JA3 that does not match the legitimate application the decoy domain implies — a browser-claimed SNI paired with a non-browser JA3 is suspicious.
- Where a TLS-terminating proxy is in path, log both fields; the front collapses the moment the inner Host is observable.
Detection rule hint:
Flag HTTPS flows where the TLS SNI and the HTTP Host header (or HTTP/2 :authority) differ, and especially where a benign CDN-fronted SNI is paired with a JA3 fingerprint inconsistent with the browser/app that domain implies — SNI/Host divergence over shared CDN infrastructure is the defining marker of domain fronting.