Does encrypting SNI put traffic beyond control? Hiding ends at the CDN

"Hide the origin IP, encrypt the SNI, and nobody can touch that traffic." I hear this claim in infrastructure design discussions from time to time. It is half right. The claim skips the question of who observes, and where. Hiding techniques target observers on the path. The endpoint that receives the request, decrypts it, and decides the response was never their target. And on the modern web, that endpoint is usually a CDN.
Where SNI sits in ClientHello and what it exposes
The short answer: SNI (Server Name Indication) sits in the server_name extension of ClientHello, the first message of a TLS handshake.1 When a single IP serves thousands of domains, as a CDN does, the server picks the right certificate by reading this value. The problem: in traditional TLS this field travels in plaintext. The payload is encrypted, but any network device along the path can read the destination domain. Corporate firewall filtering and carrier-side policy enforcement have both operated at exactly this point.
The two conditions ECH requires
ECH (Encrypted Client Hello) is a TLS 1.3 extension that encrypts ClientHelloInner, which carries the real SNI, and places it inside ClientHelloOuter. It succeeds ESNI and became a standard in March 2026 as RFC 9849.2
For ECH to actually work, two things must both be in place.
- DNS publication: the authoritative DNS publishes an ECHConfigList, one or more ECHConfig structures, in the
ech=SvcParam of an HTTPS (type65) record. - Client encryption and endpoint decryption: the client selects an ECHConfig, encrypts ClientHelloInner with its public key, carries the ciphertext in ClientHelloOuter's ECH extension, and the edge decrypts the Inner with the corresponding private key.
Without a DNS ECH configuration, a client has nothing with which to offer ECH and sends a normal ClientHello. If it receives a configuration that the endpoint cannot process, it may enter the retry flow or fail the handshake. This is not a simple rule that always downgrades to plaintext after an authenticated failure.2 A common confusion hides here. Hosting an HTTPS record with ech= on a DNS service such as Route 53 satisfies only condition (1). If the CloudFront edge does not perform (2), ECH does not exist. Record hosting and edge decryption are separate features.

Which layer controls what
Content control, whether corporate filtering, regional policy, or legal compliance, does not happen at one point. Each layer observes different data and yields to different hiding techniques.
| Layer | Location | What it observes | Hidden by encryption? |
|---|---|---|---|
| DNS transport | On-path observer | Unencrypted domain queries | Yes, via DoH/DoT |
| DNS resolution | Recursive resolver | Names queried by the client | No. The resolver terminates DoH/DoT |
| SNI inspection | On-path device | Plaintext SNI | Yes, via ECH |
| CDN / application | Destination edge | The full request | No. The endpoint holds the keys |
The last row carries the conclusion of this article. The CDN holds the key that decrypts ECH, so the ClientHello information hidden from on-path observers is not hidden from that CDN. Hiding techniques reduce the number of observers; they do not change the endpoint's decision.
For a layer-by-layer comparison of South Korean DNS, IP, and SNI controls and international overblocking cases, continue with Where does website blocking happen?.
A 451 and a connection reset say different things
The layer model pays off immediately in diagnosis. Each layer leaves a different failure fingerprint.
- DNS-resolution phase: name resolution itself fails. You see resolver responses such as NXDOMAIN.
- TLS-handshake phase: the connection ends after ClientHello and no HTTP status appears. This fingerprint alone does not identify which component closed it.
- HTTP-response phase: an HTTP response such as
451 Unavailable For Legal Reasons3 or403arrives after TLS. That classifies the phase; theServerheader, response body, and operator logs are still needed to distinguish a CDN, proxy, or origin response.

The key insight: an HTTP status code proves the exchange reached the HTTP-response phase. That distinguishes it from a connection ending just after ClientHello. A 451 alone does not identify whether the CDN, an intermediary proxy, or the origin produced it. Actor attribution requires corroborating response markers and operator logs, as this case provides.
The operator's side records the control
In this case, the event behind the visitor's 451 also appeared in the zone operator's account. Cloudflare recorded the report and its mitigation under Abuse Reports in the dashboard. The screen shows the structure plainly.

Two things stand out. First, the mitigation in this case is a Geo block. A CDN can use request-origin information to apply policy to traffic from a jurisdiction. Jurisdiction scoping alone does not prove that a CDN acted, however; an on-path operator can also use source-network or location signals. Here, the Cloudflare response page and dashboard record together locate the mitigation at the CDN. Second, the grounds are documented. The report date, mitigation status, and target entity are managed per report, and the operator gets a dispute path through a Trust & Safety review.

The evidence field quotes the category designated by the regulator and records that "the law does not give Cloudflare discretion to diverge from this mandate." For this report, the console presents a legal order as the basis and documents its scope. That cannot establish the basis of every CDN block, but it shows how one control action is recorded in practice.
ECH varies by CDN
Even "hosted behind a CDN" splits into different SNI exposure profiles depending on which CDN. As of July 2026:
- Cloudflare: supports ECH. It is enabled by default on Free zones, while other plans can enable it under Edge Certificates.4 Cloudflare publishes the ECH configuration and decrypts ClientHelloInner at the edge. Both conditions are met.
- AWS CloudFront: the viewer-protocol and cipher documentation, checked on July 16, 2026, does not state viewer-side ECH support.5 Route 53's ability to host an
ech=record does not establish CloudFront edge decryption. - Server side: NGINX 1.29.4 shipped ECH support and, at publication, required OpenSSL's ECH feature branch.6 The final OpenSSL 4.0 release also includes RFC 9849 ECH.7 Those separate announcements do not guarantee build compatibility for a specific NGINX/OpenSSL pair. Verify build flags, link compatibility, and handshake interoperability before deployment.
SNI and ECH FAQ
What is SNI encryption?
For SNI encryption, the client puts the true destination in ClientHelloInner, selects a public key from an ECHConfig in the ECHConfigList, and encrypts the encoded Inner. The ciphertext travels in ClientHelloOuter's ECH extension, while the Outer carries a public name. The endpoint with the corresponding private key reconstructs the Inner.2 ECH does not hide the destination from the CDN that processes the HTTP request and response.
Where does SNI appear in ClientHello?
Without ECH, the true domain appears in plaintext in ClientHello's server_name extension. With ECH, the true domain moves into the encrypted Inner server_name, while the Outer carries the ECH configuration's public_name. Seeing only the Outer SNI does not reveal the site the user requested.
What is cloudflare-ech.com?
cloudflare-ech.com is the public SNI Cloudflare uses in ClientHelloOuter for ECH traffic.4 It does not mean the user visited that site. The real domain sits in encrypted ClientHelloInner and only the Cloudflare edge can read it. A shared outer name gives many ECH-enabled sites the same appearance on the network path.
How do I verify that ECH is actually working?
A DNS record alone is not proof. Work through this ECH verification checklist end to end.
- Run
dig <domain> type65 +shortand confirm that the HTTPS record'sech=SvcParam publishes an ECHConfigList. - Use a current browser. Firefox has enabled ECH by default since version 119, but enterprise policy, a trusted transparent proxy, or family-safety settings can disable it.8
- Use encrypted DNS such as DoH or DoT as well. ECH can hide the real TLS SNI while a plaintext DNS query still reveals the destination.
- Use Cloudflare's Browser Security Check, the test Mozilla recommends, to confirm that the client negotiated ECH.8
- When deeper evidence is needed, capture the handshake and confirm that the provider's public name, not the real domain, appears as the Outer SNI.
- Confirm that certificate validation and the HTTP response for the real domain still succeed. DNS publication, client use, and endpoint decryption must all work.
Pinning down the layer
A reproducible procedure for classifying connection problems you meet in operations.
Check ECH publication. Look for ech= in the domain's HTTPS record.
dig example.com type65 +short
The result has three forms. A domain publishing ECH includes an ech SvcParam in its HTTPS record. A domain may publish other parameters, such as alpn or IP hints, without ECH. A domain with no HTTPS record returns an empty answer. Check for the ECH configuration, not merely a nonempty response. The example below shows an older dig rendering the complete HTTPS record as a binary blob.
$ dig example-a.org type65 +short
\# 136 000100000100060268330268320004000868152384AC43DE92000500
470045FE0D004165002000206D6ED8B048EDBCDA3DBCDE74FC3CF52E
D8C6DB3F991F733282F117CDA36F8A6B0004000100010012636C6F75
64666C6172652D6563682E636F6D0000000600202606470030360000
0000000068152384260647003037000000000000AC43DE92
$ dig example-b.org type65 +short
$
The ech= ECHConfigList sits in that blob. Decode the run spanning the third and fourth lines, 636C6F75 64666C6172652D6563682E636F6D, as ASCII and you get cloudflare-ech.com: the public name the Outer ClientHello will carry. Condition (1), DNS publication of the ECHConfigList, is met.
One trap: some dig versions ignore dig -t HTTPS or dig https as an "invalid type" and silently fall back to an A record query. The numeric type65 form is safe. If you suspect a resolver strips HTTPS records, cross-check your local resolver against public ones (@1.1.1.1, @8.8.8.8).
Find where the connection dies. Compare handshakes to the same IP while changing only the SNI value.
openssl s_client -connect <IP>:443 -servername example.com
If the connection ends right after ClientHello for one SNI while another SNI receives a handshake response, the outcome is SNI-dependent. This comparison alone cannot identify whether an on-path device, CDN edge, or virtual-host configuration created the difference. The two outputs differ from the first line.
Full output of a connection cut right after ClientHello
$ openssl s_client -connect <edge-ip>:443 -servername example-a.org
Connecting to <edge-ip>
CONNECTED(00000003)
error:0A000126:SSL routines::unexpected eof while reading:ssl/record/rec_layer_s3.c:703:
---
no peer certificate available
---
No client certificate CA names sent
Negotiated TLS1.3 group: <NULL>
---
SSL handshake has read 0 bytes and written 1552 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Protocol: TLSv1.3
This TLS version forbids renegotiation.
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
error:0A000197:SSL routines:SSL_shutdown:shutdown while in init:ssl/ssl_lib.c:2804:
Three lines carry the story: unexpected eof while reading, no peer certificate available, and read 0 bytes. We wrote 1552 bytes of ClientHello and the connection closed before a single byte came back. No certificate, no cipher negotiation, no HTTP status code.
When the same command reaches the server, the certificate chain pours out from the first screen.
Full output of a handshake that completed to the server
$ openssl s_client -connect <edge-ip>:443 -servername example-b.com
Connecting to <edge-ip>
CONNECTED(00000003)
depth=3 C=US, O=Internet Security Research Group, CN=ISRG Root X2
verify return:1
depth=2 C=US, O=ISRG, CN=Root YE
verify return:1
depth=1 C=US, O=Let's Encrypt, CN=YE1
verify return:1
depth=0 CN=example-b.com
verify return:1
---
Certificate chain
0 s:CN=example-b.com
i:C=US, O=Let's Encrypt, CN=YE1
a:PKEY: EC, (prime256v1); sigalg: ecdsa-with-SHA384
v:NotBefore: Jun 20 00:37:09 2026 GMT; NotAfter: Sep 18 00:37:08 2026 GMT
1 s:C=US, O=Let's Encrypt, CN=YE1
i:C=US, O=ISRG, CN=Root YE
...
---
Server certificate
-----BEGIN CERTIFICATE-----
(omitted)
-----END CERTIFICATE-----
subject=CN=example-b.com
issuer=C=US, O=Let's Encrypt, CN=YE1
---
Peer signing digest: SHA256
Peer signature type: ecdsa_secp256r1_sha256
Negotiated TLS1.3 group: X25519MLKEM768
---
SSL handshake has read 4963 bytes and written 1620 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Protocol: TLSv1.3
Verify return code: 0 (ok)
---
read 4963 bytes, a negotiated cipher suite TLS_AES_256_GCM_SHA384, and Verify return code: 0 show that the TLS peer returned a handshake response. Side by side, the outputs classify whether failure happened before or after that response and establish SNI dependence. Identifying the actor still requires path evidence, response markers, or operator logs.
Judgment
Four takeaways from the architecture standpoint.
- Hidden does not mean uncontrollable. Origin IP hiding and SNI hiding (ECH) target third-party observers. If the destination CDN decides to refuse by policy, neither technique changes that decision.
- The CDN becomes an important control point. The more traffic moves behind CDNs, the more observation, blocking, and compliance functions collect there. Origin protection improves, while governance and availability depend more heavily on the provider.
- A single signal classifies a phase, not an actor. A status code places the exchange before or after an HTTP response; different outcomes by SNI on the same IP establish SNI dependence. Additional evidence must distinguish the CDN, an on-path device, and the origin.
- ECH is a hidden variable in CDN selection. HTTPS record publication and edge decryption support differ by CDN and directly shape a service's privacy and exposure profile.
These control points and provider dependencies connect to the design decisions in our Cloud / AWS in practice articles.
If you need a team that designs infrastructure around these control and compliance layers, start with Cloud & Infrastructure; for transformation strategy including regulatory response, see AX Consulting.
References
Sources & notes8ExpandCollapse
Footnotes
-
RFC 6066, "Transport Layer Security (TLS) Extensions." Defines the
server_nameextension in ClientHello and the SNI format. https://www.rfc-editor.org/rfc/rfc6066 ↩ -
RFC 9849, "TLS Encrypted Client Hello" (March 2026). The standard that replaces ESNI. https://www.rfc-editor.org/rfc/rfc9849 ↩ ↩2 ↩3
-
RFC 7725, "An HTTP Status Code to Report Legal Obstacles" (451). https://www.rfc-editor.org/rfc/rfc7725 ↩
-
Cloudflare SSL/TLS documentation, "ECH Protocol." Explains ClientHelloInner, ClientHelloOuter,
cloudflare-ech.com, and plan-specific enablement. https://developers.cloudflare.com/ssl/edge-certificates/ech/ ↩ ↩2 -
Amazon CloudFront Developer Guide, "Supported protocols and ciphers between viewers and CloudFront". As checked on July 16, 2026, the page does not state viewer-side ECH support. Absence from this page alone is not treated as proof of universal non-support. https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/secure-connections-supported-viewer-protocols-ciphers.html ↩
-
NGINX Community Blog, "Encrypted Client Hello Comes to NGINX." NGINX 1.29.4 ECH support and its original build requirement for the OpenSSL ECH feature branch. https://blog.nginx.org/blog/encrypted-client-hello-comes-to-nginx ↩
-
OpenSSL Library, "OpenSSL 4.0 Final Release - Live" (April 14, 2026). The final release includes support for RFC 9849 ECH. https://openssl-library.org/post/2026-04-14-openssl-40-final-release/ ↩
-
Mozilla Support, "Understand Encrypted Client Hello (ECH)." Covers the Firefox 119 default, the recommendation for encrypted DNS, and disablement in enterprise or family-safety environments. https://support.mozilla.org/en-US/kb/understand-encrypted-client-hello ↩ ↩2


