Skip to content

HTTPS Interception

Probe inspects HTTPS by acting as a man-in-the-middle. It terminates the TLS handshake using a per-host leaf certificate signed by Probe’s own CA, then opens a separate TLS connection upstream to the real origin. With the CA installed and trusted on your device, the leaf is accepted and the encrypted stream becomes readable in the Detail panel.

This page explains the mechanics — what’s happening on the wire, how the system proxy is configured, and how to chain Probe behind a corporate upstream proxy.

A typical HTTPS request through Probe goes through these steps:

  1. The client sends CONNECT api.example.com:443 HTTP/1.1 to Probe (port 9099 by default).
  2. Probe replies 200 Connection established and starts a TLS handshake as the server.
  3. On the fly, Probe asks its GuideAuthority to mint a leaf certificate for api.example.com, signed by the Probe CA. The leaf is generated once and cached for the session.
  4. The client validates the leaf — it chains to the Probe CA, which you’ve already trusted on this device, so the handshake succeeds.
  5. Probe opens its own TLS connection to api.example.com:443 upstream.
  6. Bytes flow client → Probe → origin and origin → Probe → client. Probe holds the plaintext in the middle and writes it to the log.

The leaf certificate marks itself with IsCa::ExplicitNoCa (BasicConstraints CA:FALSE plus a Subject Key Identifier). Without that extension iOS rejects the leaf even if the CA is trusted, so it’s not optional — it’s a requirement of Apple’s stricter validation.

If the CA isn’t installed yet, see Set up the CA certificate. For phones, see Mobile debugging.

When you click Start, Probe flips your operating system’s HTTP and HTTPS proxy to point at 127.0.0.1:9099. When you click Stop — or quit the app — the previous settings are restored.

  • macOS uses networksetup to update every active network service (Wi-Fi, Ethernet, Thunderbolt). Bypass entries cover loopback, link-local, and private LAN ranges so local services don’t get tunneled through Probe.
  • Windows writes to the WinINET registry keys and broadcasts INTERNET_OPTION_REFRESH so apps that read WinINET (Chromium, Edge, most desktop apps) pick up the change immediately.

A handful of apps ignore the system proxy — Firefox has its own setting, some Electron apps respect HTTP_PROXY only on launch, and Java apps need -Dhttp.proxyHost. For those, set the proxy explicitly to 127.0.0.1:9099.

If your network forces traffic through a corporate proxy, Probe can chain through it. Set the standard HTTPS_PROXY (and HTTP_PROXY) environment variables before launching Probe — the Rust core picks them up and forwards intercepted traffic through that upstream after decrypting it locally.

Terminal window
# macOS / Linux shell
export HTTPS_PROXY=http://corp-proxy.internal:8080
open -a Probe
Terminal window
# Windows
$env:HTTPS_PROXY = "http://corp-proxy.internal:8080"
& 'C:\Program Files\Probe\Probe.exe'

NO_PROXY is honored too — list domains that should connect directly without going through the upstream.

Probe strips the Accept-Encoding header on every outgoing request before forwarding it upstream. Origins respond with uncompressed bodies, so what you see in the log is the actual JSON, HTML, or text — no gzip/br decoding step needed in the UI.

The trade-off: response sizes shown in the Summary tab are the uncompressed sizes, which won’t match what the client would have received over the network if compression was negotiated. For most debugging this is what you want; if you specifically need to test compression behavior, disable that step in Settings.