# How CFnew Implements Encrypted Client Hello (ECH) for TLS Privacy

> Learn how CFnew implements Encrypted Client Hello ECH for enhanced TLS privacy by encrypting SNI and preventing domain interception. Discover its DNS-over-HTTPS and Chrome fingerprint techniques.

- Repository: [byJoey/cfnew](https://github.com/byJoey/cfnew)
- Tags: deep-dive
- Published: 2026-05-23

---

**CFnew implements Encrypted Client Hello by fetching ECH configurations via DNS-over-HTTPS, enforcing TLS-only connections, and injecting Chrome fingerprint parameters into proxy URLs, effectively encrypting the Server Name Indication during TLS handshakes to prevent domain interception.**

Encrypted Client Hello (ECH) is a TLS extension designed to conceal the Server Name Indication (SNI) from network observers during the initial handshake. The open-source CFnew project, hosted at `byJoey/cfnew`, provides a production-ready implementation for Cloudflare Workers that automatically configures ECH support through KV storage and dynamic request manipulation. This article breaks down the specific source code mechanisms that enable ECH protection, from DNS configuration fetching to client fingerprint masking.

## What Is Encrypted Client Hello?

**Encrypted Client Hello (ECH)** is a privacy-preserving extension to the TLS 1.3 protocol that encrypts the Client Hello message, which traditionally exposes the target domain name (SNI) in plaintext. By encrypting this handshake data, ECH prevents middleboxes, ISPs, and passive observers from identifying the destination domain, mitigating both surveillance and domain-fronting attacks. CFnew leverages this standard to ensure that proxy connections reveal only the Cloudflare edge IP, not the actual backend service domain.

## How CFnew Implements ECH

CFnew integrates ECH support through a five-stage pipeline that activates when the `ech` KV configuration key is set to `"yes"` or `"true"`.

### Activating the ECH Flag

The request handler entry point checks KV storage for the `ech` key and sets the global `enableECH` variable. This boolean flag controls all subsequent ECH logic in the request lifecycle. According to the source code, this initialization occurs in the main worker export: [`明文源吗#L6665-L6670`](https://github.com/byJoey/cfnew/blob/main/明文源吗#L6665-L6670).

### Enforcing TLS-Only Mode

Since ECH requires encrypted TLS channels to function, CFnew automatically disables non-TLS connections when ECH is enabled. The code explicitly sets `disableNonTLS = true` and persists this constraint to KV storage, ensuring that plaintext HTTP nodes are excluded from the proxy pool: [`明文源吗#L586-L593`](https://github.com/byJoey/cfnew/blob/main/明文源吗#L586-L593).

### Fetching ECH Configuration via DNS-over-HTTPS

The `fetchECHConfig(domain)` function retrieves the ECH configuration by querying DNS HTTPS records (Type 65). It first attempts to resolve `cloudflare-ech.com` using Google DNS-over-HTTPS, falling back to a user-defined custom domain if necessary. The function decodes base64 payloads, extracts the `ech=` value, and stores a debug trace in `echDebugInfo`: [`明文源吗#L2440-L2596`](https://github.com/byJoey/cfnew/blob/main/明文源吗#L2440-L2596).

### Injecting Diagnostic Headers

For transparency and debugging, CFnew adds response headers indicating ECH status. When active, the worker returns `X-ECH-Status: ENABLED` and includes `X-ECH-Config-Length` showing the byte size of the retrieved ECH payload: [`明文源吗#L2770-L2773`](https://github.com/byJoey/cfnew/blob/main/明文源吗#L2770-L2773).

### Masking Client Fingerprints

To ensure compatibility with ECH handshakes, CFnew modifies outbound proxy link generation. When `enableECH` is true, the system appends `fp=chrome` to the connection parameters, forcing a Chrome-compatible TLS fingerprint that supports ECH negotiation: [`明文源吗#L7892-L7894`](https://github.com/byJoey/cfnew/blob/main/明文源吗#L7892-L7894).

## Configuration and KV Storage

CFnew exposes ECH controls through KV keys and UI toggles. The implementation reads configuration values early in the request lifecycle to determine whether to activate the ECH pipeline: [`明文源吗#L7778-L7790`](https://github.com/byJoey/cfnew/blob/main/明文源吗#L7778-L7790).

Available configuration options:

- **`ech`**: Set to `"yes"` or `"true"` to enable ECH processing
- **`customECHDomain`**: Optional custom domain for fetching ECH configs (defaults to `cloudflare-ech.com`)

These values are typically set via the UI toggle **"启用 ECH (Encrypted Client Hello)"** and the corresponding custom domain field.

## Code Examples

Enable ECH programmatically via KV storage:

```javascript
// Activate ECH support
await setConfigValue('ech', 'yes');

// Optional: Use custom ECH domain instead of cloudflare-ech.com
await setConfigValue('customECHDomain', 'ech.example.com');

```

Verify ECH status from client responses:

```javascript
fetch('https://<worker-domain>/test-api')
  .then(response => {
    console.log('ECH Status:', response.headers.get('X-ECH-Status')); // "ENABLED"
    console.log('Config Length:', response.headers.get('X-ECH-Config-Length'));
  });

```

Inspect the ECH configuration fetch results internally:

```javascript
// Inside the worker context
const echConfig = await fetchECHConfig(customECHDomain);
console.log('Raw ECH config:', echConfig);
console.log('Resolution trace:', echDebugInfo);

```

Generate ECH-compatible proxy links:

```javascript
// Link construction includes Chrome fingerprint when ECH is active
const link = `${proto}://${user}@${safeIP}:${port}`
  + `?encryption=none&security=tls&sni=${workerDomain}`
  + `&fp=${enableECH ? 'chrome' : 'randomized'}`
  + `&type=ws&host=${workerDomain}&path=${wsPath}`;

```

## Summary

- **ECH Activation**: Controlled by the `ech` KV key, read at the worker entry point to set `enableECH`
- **TLS Enforcement**: Automatically disables non-TLS nodes when ECH is active via `disableNonTLS`
- **DoH Resolution**: `fetchECHConfig()` retrieves Type 65 HTTPS records using Google DNS, with fallback support for custom domains
- **Header Transparency**: Injects `X-ECH-Status` and `X-ECH-Config-Length` headers for debugging
- **Fingerprint Spoofing**: Forces `fp=chrome` on proxy links to ensure ECH handshake compatibility

## Frequently Asked Questions

### What happens if the ECH configuration fetch fails?

If `fetchECHConfig()` cannot resolve the ECH record from either the default `cloudflare-ech.com` or the custom domain, the function returns `null` or an empty string. The proxy continues operating but without ECH encryption, and the debug trace in `echDebugInfo` logs the specific DNS resolution failure.

### Why does CFnew require a Chrome fingerprint when ECH is enabled?

ECH handshakes require specific TLS extensions and cipher suites that match modern browser implementations. By appending `fp=chrome` to proxy URLs, CFnew ensures the downstream connection presents a Client Hello packet that Cloudflare recognizes as ECH-capable, preventing handshake failures that would occur with randomized fingerprints.

### How do I verify that ECH is actually working in my deployment?

Send a test request to your CFnew worker endpoint and inspect the response headers. You should see `X-ECH-Status: ENABLED` confirming the feature is active, and `X-ECH-Config-Length` indicating successful retrieval of the ECH configuration from DNS. Additionally, packet captures should show encrypted SNI data in the TLS 1.3 Client Hello message.

### Can I use ECH with non-TLS proxy nodes?

No. The implementation explicitly forces TLS-only mode when ECH is enabled by setting `disableNonTLS = true`. This constraint is necessary because ECH extensions only function within encrypted TLS 1.3 handshakes; plaintext HTTP connections expose the target domain regardless of ECH configuration.