VPN bypass IP leak affecting all Android 16 devices

On Android 16, a regular app with no special permissions can leak the user’s real IP, even with “Always-On VPN” + “Block connections without VPN” turned on.

Android Security Team closed the issue as “Won’t Fix (Infeasible)”. GrapheneOS on the other hand has already released a fix.

12 Likes

Google: Won’t fix/infeasible

Graphene: Already patched

Google isn’t even pretending to care anymore, are they?

7 Likes

Did they ever?

I mean, there was a time when they would bother with a quick security patch…

Clearly those days are long gone

They were not outwardly evil then. Times have changed. Customer behavior needed to catch up yesterday. But people continue to take the abuse.

W GrapheneOS

9 Likes

even if you didn’t care about the privacy or security gains, Graphene would be worth it just for fixing Googles BS

I think it suffers from the same problem as Linux if adoption is to be increased among the populous:

Installation, apps, and lack of some tech savvy know how of something new to do the same things you normally do on your consumer electronics.

GrapheneOS is extremely easy to use IMO. I think pretty much anyone who knows how to use a cell phone could use it easily with sandboxed play services, or with Aurora.

3 Likes

Similar:
Connectivity check bypasses / leaks through “Always-on VPN / Block connections without VPN” issues raised by Mullvad in 2022 on Google’s issue tracker:

Incomplete Android documentation about blocked connections, not mentioning said bypass/leak
(“Assigned”, documentation not fixed since 2022)
Current Android documentation for reference

Feature request for not bypassing VPN, actual discussion
(“Won’t fix / Intended”)

Only solution is disabling connectivity checks altogether or alternatively routing the checks to a different, trusted server (both require ADB/root, if not in ROM settings).

1 Like

@uninvitedfriend if I may ask, if this issue was opened by Mullvad in 2022, why was it only just fixed GOS? Or was that a diff. issue?

It is an older issue

Which Mullvad did mention GOS having a solution for already in one of the issues linked here:

Hey! Any chance of re-opening this issue/feature request since it has gotten quite a lot of upvotes?

AOSP based GrapheneOS exposes this functionality in a separate settings screen under “Network & connectivity” → “Internet connectivity checks” where the user can select one of the following:

GrapheneOS server

Standard (Google) server

Off

Maybe something similar can be done in the AOSP?

Which is the same suggestion @uninvitedfriend made assuming you trust GOS, though you can’t use a different server you choose.

This new one was fixed here in release 2026050400:

disable registerQuicConnectionClosePayload optimization to fix VPN leak

Though the patch has not yet reached stable as they had to pull it and make another release.

I also want to bring attention to their response in the discussion for the release about internet connectivity checks here:

Internet connectivity checks aren’t a VPN leak. They bypass the Owner user VPN by design and are important for VPN support. They enable choosing a connection with internet access including for the VPN and are how captive portals are detected. The connectivity checks trigger notifying the user about a captive portal to use the captive portal handling app which is another special system component bypassing the VPN by design to enable handling the captive portal without disabling the VPN. The alternative would be having to create another profile to use the web browser without a VPN since VPNs are per-profile.

Let me know if I got anything wrong please.

1 Like

Right, I got that from this very issue a while back, so all credits to the participants there.
Anyway, as I don’t have a Pixel at hand, wasn’t there actually a setting for which server to use? Or was it just GOS, Google and Disabled or something?

Regardless, you could technically use another server, either by manually/programmatically setting it via ADB or with root. I don’t know if it is exclusive to root mode, but the firewall app “De1984” for example has a setting for which server to use.
ADB would be (for completeness all settings):

adb shell settings put global captive_portal_http_url http://...
adb shell settings put global captive_portal_https_url https://...
adb shell settings put global captive_portal_fallback_url http://...
adb shell settings put global captive_portal_other_fallback_url http://...
For verification:
adb shell settings get global captive_portal_... [without URL]

…or for disabling:
adb shell settings put global captive_portal_detection_enabled 0

A server would just need to serve a 204 code, so I guess you could also self-host this.

Public server addresses for the privacy-minded are for example:

GrapheneOS’s servers

http://connectivitycheck.grapheneos.network/generate_204 https://connectivitycheck.grapheneos.network/generate_204

German IT security researcher Mike Kuketz’s servers

http://captiveportal.kuketz.de
https://captiveportal.kuketz.de

Yes, like @anonymous602 said, it is a different issue and comes down to intent philosophy. Google has a legitimate reason not to “fix” this one, so servers are actually reachable to check if a connection even reaches the internet.
(Also, Android might bug you about this, from the exclamation mark next to WiFi/mobile to a notification about not being able to reach the internet.)
But this check is not really necessary AFAIK, you could just ignore it and the connection will probably still work. The descriptor is also ambiguous to misleading, because not all connections are blocked. This is where the opposite opinion comes from.

Someone please correct me if I’m wrong, this is how I understand things.

1 Like

I can confirm it is only those three options.

GOS doesn’t support root or ADB either I believe, so I would avoid doing either.

For this I’m not going to act like I really know so I’m just going to refer back to the response I linked to from GOS.

1 Like

I see, I guess they discourage it from an attack surface standpoint, which is fair. Those with a lower risk or only connecting (if not also only enabling temporarily) to trusted devices could still use it, should they need to.
Then again, since there is already a (default) setting to use their servers as you confirmed, so it’s pointless to use the above commands. (Also not many public 204 servers from reputable, privacy-advocating sources, if not self hosting.)

I see where they are coming from. It’s not only convenient to have a captive portal check in place, some features cease to work.
However, AFAIK your internet would still work fine without it, and you could still manually connect to a VPN. Not 100% sure as I lack ADB at the moment, but maybe I’ll play around some and disable the check and the captive portal app to see what’s breaking, with which I may update the post.

These are probably unrelated but does the fix by GrapheneOS also fix this issue? Where in Android 16 after updating a VPN app the system may end up in a state where the VPN app is no longer able to reach the internet. I have been having so many issues with ProtonVPNs app because of it.

I don’t believe it is related and likely doesn’t fix it. I’d have to wait for another VPN update to test, but a restart should fix any issues.

In contrast, GrapheneOS, a security-focused Android-based OS, quickly patched the issue in its codebase.

Cool!

This bug is pretty concerning, Android 16 introduced various weird issues, including cases where Mullvad stops working after an app update until you restart the device.

The same thing happened to me with Proton (but not every time after an update).