When a WebRTC test page prints 172.20.4.15, it has learned that a local interface exists on that network. That is a genuine disclosure, and it is not the same finding as "media left through the VPN exit". Candidate discovery and packet routing are separate mechanisms, and most leak reports merge them into one verdict. Which one you are looking at decides the fix.

Gathering runs before anything is sent

The browser enumerates local interfaces, sends a binding request to a STUN server and asks a TURN server for an allocation, then writes the results into the session description as candidate lines. All of that completes with no call, no media and no peer. A list of candidates is therefore a record of discovery, not of transport.

Modern browsers may replace a host candidate's literal address with an mDNS .local name, so the page cannot read the private IP. The local network still sees the multicast queries that resolve that name, so the address is hidden from the application rather than removed from the wire.

Permutation matters too: a fresh page load gathers a new set, using a different TURN allocation and possibly a different reflexive mapping. Two runs that disagree are not necessarily two different configurations.

Three candidate types, three kinds of evidence

Each line is derived from a different observation. Each type answers a different question, and the table separates them by what they can and cannot establish.

CandidateDerived fromWhat it establishesWhat it cannot establish
HostAn interface on the deviceA local address exists in that networkThat the peer can reach it
Server-reflexiveA STUN binding responseHow a NAT mapped this sourceWhich exit the media will use
Peer-reflexiveA connectivity check that arrivedAn address seen by the far sideThat it was ever advertised
RelayA TURN allocationThe relay server accepted the sessionThat the relay carries the call

A relay candidate is routinely mistaken for the user's internet address. It belongs to the TURN server, and its presence shows that a relay was available, not that the browser chose it. The same confusion runs the other way with host candidates, where an mDNS name hides the address from the page while the network still carries the queries. Read the type before you read the value.

The selected pair answers the routing question

ICE pairs every local candidate with every remote one, runs connectivity checks over each, and nominates a winner. That nominated pair, visible in the browser's own diagnostics, carries the media. Everything else in the list is a possibility that lost.

The winner tells you the shape of the path. Relay-to-relay goes through the TURN server, a host pair stays on the local network, and a server-reflexive pair goes direct through NAT. That is the fact a VPN check needs, and it is a different fact from the address list. Two calls with identical candidate lists can take different pairs.

Unselected candidates were still gathered, and gathering is network traffic that leaves the machine. A call that ultimately used the relay does not mean nothing was disclosed while the list was built.

Controls map to goals, not to a leak score

The WebRTC IP-handling specification describes several policies: using only the interface that carries the default route, using all interfaces, and disabling non-proxied UDP so traffic must go through a relay or proxy. Each trades connectivity and latency for a different kind of exposure. Which one a browser implements, and under what name, varies by platform and release.

Choose the policy from the goal. Hiding local addresses from a page is one goal; preventing direct peer-to-peer traffic is another; keeping every packet inside the tunnel is a third. The first is mostly about what the application learns, the second about which path is permitted, and the third has to be enforced at the platform or VPN boundary as well.

Whatever control you pick, verify both halves: run the gathering test and record candidate types, then inspect the selected pair during a real session. A clean address list with a direct media path is still a path you did not intend.

འབྲེལ་བའི་རྩོམ་ཡིག