AnonymFlow
securite-reseauINFO

IPv6 VPN leaks: your system prefers IPv6, and that is exactly why it leaks

An IPv6 leak is not a bug in your VPN. It is your operating system obeying RFC 6724, which tells it to prefer IPv6 over IPv4. If the tunnel only carries IPv4, the preferred path goes around it. How to check, and the one line that fixes it on WireGuard.

By Eric Gerard · Editor · AnonymFlow6 min readPhoto via Pexels

Your VPN is connected. The tunnel is up, the client says protected, and your IPv4 traffic really is going through it. And a website you visit still logs your real address, because it reached you over IPv6.

There is no failure here to find. This is two correct systems disagreeing, and the disagreement is written into a standard.

Your system is not misbehaving, it is following RFC 6724

When a destination is reachable over both IPv4 and IPv6, something has to choose. That something is RFC 6724, which defines a default policy table for address selection. Three of its rows matter here:

Prefix        Precedence Label
::1/128               50     0
::/0                  40     1
::ffff:0:0/96         35     4

::/0 is IPv6 in general. ::ffff:0:0/96 is how IPv4 addresses are represented in that table. Forty beats thirty-five, and the destination selection rule is explicit: if Precedence(DA) > Precedence(DB), then prefer DA.

The RFC states the consequence in plain language rather than leaving you to infer it: another effect of the default policy table is to prefer communication using IPv6 addresses to communication using IPv4 addresses, if matching source addresses are available.

So for every dual-stack site you visit, your operating system reaches for IPv6 first. That is correct behaviour, and it long predates your VPN.

Why that turns into a leak

Now put a VPN on top that only carries IPv4.

Your machine still holds a native IPv6 address from your ISP. The tunnel does not claim IPv6 traffic, so nothing intercepts it. Your system, following the rule above, prefers IPv6 for any destination offering it. The result is that your preferred path is the one going around the tunnel, and the protected path only gets what IPv6 could not serve.

This is why the leak is so easy to miss. It does not look like a malfunction. Your VPN reports connected because it is. Your IPv4 checks pass because they genuinely pass. The traffic that escapes is precisely the traffic your system judged best.

A technician standing at an open network rack, both hands among a bundle of white and blue patch cables running into a switch, its port lights visible behind the cabling.
A technician standing at an open network rack, both hands among a bundle of white and blue patch cables running into a switch, its port lights visible behind the cabling.

Checking, and the mistake that makes the check useless

The check is simple: with the VPN connected, look at what a site actually sees, and read the IPv6 line specifically rather than glancing at the IPv4 one and moving on.

If the IPv6 address shown belongs to your own connection instead of the VPN provider, IPv6 is outside the tunnel. If no IPv6 address appears at all, either your network has none or it is being blocked, and both are fine from a leak standpoint.

Two things ruin this check in practice:

Testing before connecting. The question is not what you look like unprotected. It is what escapes while you believe you are protected.

Testing once. A configuration that carries IPv6 today can stop after a reconnect, a change of network, or a move from Wi-Fi to mobile data, because the addresses available change with the network. A single clean result proves the setup was correct on one network at one moment.

The one line, on WireGuard

WireGuard makes the cause unusually legible, because the same setting decides both what comes in and where things go out. The wg manual defines AllowedIPs as a comma-separated list of IP (v4 or v6) addresses with CIDR masks from which incoming traffic for this peer is allowed and to which outgoing traffic for this peer is directed, and adds that the catch-all 0.0.0.0/0 may be specified for matching all IPv4 addresses, and ::/0 may be specified for matching all IPv6 addresses.

Read that as a routing instruction, which is what it is. A peer configured with only 0.0.0.0/0 directs IPv4 into the tunnel and says nothing about IPv6, so IPv6 keeps using the normal route. Adding ::/0 directs IPv6 into it as well.

One condition applies: the tunnel needs an IPv6 address of its own for this to be useful. If your provider does not assign one, routing ::/0 into a tunnel with no IPv6 endpoint does not create IPv6 connectivity. It is at that point that blocking IPv6 outright becomes the honest fallback rather than a shortcut.

Blocking IPv6 works, and costs something

Disabling IPv6 on the machine removes the preferred path, so everything falls back to IPv4 and into the tunnel. It is effective and it is what several VPN clients do under the label IPv6 leak protection.

The cost is real though. You lose IPv6 for everything else on that machine, including networks where it is the only usable transport, and the setting outlives the reason you changed it. Six months later, an unrelated connectivity problem becomes very hard to diagnose because nobody remembers IPv6 was turned off.

Routing IPv6 through the tunnel keeps the capability and solves the same problem. Prefer it whenever your provider supports it, and treat blocking as the fallback for when it does not.

The kill switch does not cover this

Worth stating separately, because the two get conflated in the same settings screen.

A kill switch watches for the tunnel going down and cuts traffic when it does. An IPv6 leak happens while the tunnel is up. There is no drop to detect, no failure event, nothing for the switch to react to. A correctly working kill switch will sit there doing its job perfectly while IPv6 traffic walks past it.

If your client offers IPv6 leak protection as a separate toggle, that is a different mechanism, and having one does not give you the other.

The short version

An IPv6 leak is not your VPN breaking. It is RFC 6724 telling your system to prefer IPv6, a tunnel that only carries IPv4, and the entirely logical outcome of those two facts.

Check with the VPN connected, read the IPv6 line, and repeat after changing networks. On WireGuard, AllowedIPs is the setting that decides it, and ::/0 is what directs IPv6 into the tunnel. Where the tunnel has no IPv6 of its own, blocking IPv6 is a legitimate fallback with a cost you should note down somewhere you will find it later.

The default policy table, the precedence values, the destination selection rule and the statement that the table prefers IPv6 communication over IPv4 are taken from RFC 6724. The definition of AllowedIPs and the catch-all notation for 0.0.0.0/0 and ::/0 are taken from the wg(8) manual page. Both were checked at the time of writing.

Editorial pick
4.6 / 5

Secure your connection with NordVPN

Threat Protection blocks trackers & malware · kill switch · 30-day money-back

Deloitte audit 202430-day guarantee14M+ users
See the offer
Everything you need to know.

Frequently asked questions

What is an IPv6 leak, exactly?

It is traffic leaving your machine over IPv6 while your VPN only carries IPv4. The tunnel is up, your IPv4 traffic is protected, and everything looks normal, but any site reachable over IPv6 sees your real address. Nothing has failed. Your VPN is doing what it was configured to do, and your operating system is doing what the standard tells it to do. The two simply disagree about which paths exist.

Why does my system prefer IPv6 in the first place?

Because RFC 6724 tells it to. The default policy table it defines gives ::/0 a precedence of 40 and IPv4-mapped addresses (::ffff:0:0/96) a precedence of 35, and the destination selection rule states that if Precedence(DA) > Precedence(DB), then prefer DA. The RFC spells out the intent directly: another effect of the default policy table is to prefer communication using IPv6 addresses to communication using IPv4 addresses, if matching source addresses are available. So for any dual-stack destination, IPv6 wins by design.

How do I know whether I am leaking?

Connect the VPN, then check what a site actually sees. If it reports an IPv6 address that belongs to your own connection rather than to the VPN provider, your IPv6 traffic is outside the tunnel. Do this with the VPN connected, not before, since the whole point is what escapes while you believe you are protected. Testing once is not enough either: a leak can appear after a reconnect, a network change, or a switch from Wi-Fi to mobile.

How do I fix it on WireGuard?

By routing IPv6 into the tunnel as well. The wg manual defines AllowedIPs as a comma-separated list of IP (v4 or v6) addresses with CIDR masks from which incoming traffic for this peer is allowed and to which outgoing traffic for this peer is directed, and notes that the catch-all 0.0.0.0/0 may be specified for matching all IPv4 addresses, and ::/0 may be specified for matching all IPv6 addresses. A configuration carrying only 0.0.0.0/0 therefore sends IPv4 through the tunnel and leaves IPv6 to find its own way. Adding ::/0 directs IPv6 into it too, provided the tunnel actually has an IPv6 address to use.

Should I just disable IPv6 instead?

It works, and it is the blunt instrument. Disabling IPv6 removes the preferred path entirely, so everything falls back to IPv4 and into the tunnel. The cost is that you lose IPv6 on that machine for everything else, including networks where it is the only usable transport, and you have to remember you did it. Routing IPv6 through the tunnel keeps the capability and solves the same problem, which is why it is the better default when your provider supports it.

Does a kill switch protect me from an IPv6 leak?

Not by itself, and this is the misunderstanding worth clearing up. A kill switch reacts to the tunnel going DOWN. An IPv6 leak happens while the tunnel is perfectly UP: there is no failure to detect and nothing to cut. Some clients do block IPv6 separately and label it IPv6 leak protection, which is a different mechanism from the kill switch even when the same settings screen presents them side by side.