An ongoing security audit of our app identified that Android leaks certain traffic, which VPN services cannot prevent. The audit report will go public soon. This post aims to dive into the finding, called MUL22-03.
We researched the reported leak, and concluded that Android sends connectivity checks outside the VPN tunnel. It does this every time the device connects to a WiFi network, even when the Block connections without VPN setting is enabled.
We understand why the Android system wants to send this traffic by default. If for instance there is a captive portal on the network, the connection will be unusable until the user has logged in to it. So most users will want the captive portal check to happen and allow them to display and use the portal. However, this can be a privacy concern for some users with certain threat models. As there seems to be no way to stop Android from leaking this traffic, we have reported it on the Android issue tracker.
Even if you are fine with some traffic going outside the VPN tunnel, we think the name of the setting (“Block connections without VPN”) and Android’s documentation around it is misleading. The impression a user gets is that no traffic will leave the phone except through the VPN. Due to this, we have reported another issue, where we suggest improving the Android documentation.
Steps to reproduce
Ensure Always-on VPN and Block connections without VPN is enabled in system settings.
Disconnect from your WiFi.
Start monitoring network traffic from and to the Android device, e.g. by running tcpdump on your router.
Connect to your WiFi.
Observe that the traffic isn't limited to VPN traffic, but also consists of DNS lookups, HTTP(S) traffic and potentially also NTP traffic.
As a comparison, the privacy and security focused Android based distribution GrapheneOS provides users with the option to disable connectivity checks. If that option is enabled, the above leaks could not be observed by us.
The connection check traffic can be observed and analyzed by the party controlling the connectivity check server and any entity observing the network traffic. Even if the content of the message does not reveal anything more than "some Android device connected", the metadata (which includes the source IP) can be used to derive further information, especially if combined with data such as WiFi access point locations. However, as such an de-anonymization attempt would require a quite sophisticated actor, most of our users are probably unlikely consider it a significant risk.
Conclusions and recommendations
There is nothing we can do in the app to fix the leaks. We can however inform our users that they exist, and be transparent about the limitations of the Android operating system. This allows everyone can make an informed decision.
As a closing note, we would like to recommend Google to adopt the ability to disable the connectivity checks, like on GrapheneOS, into stock Android.
Thoughts? What happens if you disable internet connectivity checks on grapheneOS?