// HACKER NEWS — CYBERSECURITY
Android NAT-T keepalive offload bypasses VPN lockdown
Technical report on Android VPN lockdown bypass via NAT-T keepalive offload.
Android’s Always-on VPN and “Block connections without VPN” settings create a
user-visible expectation that traffic attributable to covered applications will
not leave through a non-VPN path. A normal application can violate that boundary
through Android’s public NAT-T socket-keepalive API, causing clear, fixed-format
UDP/4500 packets to reach the physical router outside the VPN path. The runtime
evidence has three levels. A controlled access-point capture on a Pixel 8 Pro
running Android 16 build CP1A.260505.005 recorded the packets at the public
minimum 10-second interval while Always-on VPN and lockdown were enabled. A
Samsung SM-F966B running Android 16 exposed one active Wi-Fi slot through the
same public path; VPN Leak Guard selected the physical IPv4 default gateway,
observed the active callback, and recorded a continuous router-directed
active-slot lease for 24 h 32 min. On a Nothing A059 (Asteroids) running
Android 16, the same implementation selected the physical gateway and recorded
one active Wi-Fi slot. The Nothing result confirms public-path admission and the
active callback on a third OEM. No independent packet capture or duration
measurement was collected for that device. The Pixel lifecycle matrix covered
backgrounding, lock, Doze, battery saver, restricted standby bucket, Binder
freezer, and the observed force-stop, uninstall, network-loss, and reboot
boundaries.
Source history traces the failure to a collapsed trust model in
startNattKeepaliveWithFd(...): a privileged raw-fd API evolved into a public
UdpEncapsulationSocket path, resource validation was added and reverted, and
admission no longer authenticates the fd/resource pair or enforces the original
caller UID’s current VPN policy before offload. In an F-Droid/IzzyOnDroid study
of 4,679 distinct stored Git origins, the scanner detected no Android framework
IPsec, IKE, or NAT-T API use; manual audit found 73 Android VpnService apps.
Runtime confirmation across three OEMs and two confirmed WLAN families, the
shared Android 12+ framework path, and firmware coverage across seven WLAN
families representing 91.24% of estimated Android-derived shipments establish
device-class exposure affecting most Android 12+ devices. The remaining 8.76%
is unresolved.
VPN lockdown governs routing and confinement in addition to encryption. Users
and administrators expect covered applications to fail closed when the VPN is
unavailable and to withhold their real network identity from destinations
outside the tunnel. Prior VPN-leak research has studied routing exceptions,
IPv6 and DNS leaks, WebRTC address exposure, VPN client ecosystems, and shared
VPN infrastructure failures [1; 2; 3; 4; 5; 6; 7]. Android also delegates some
application-triggered packet emission to system_server, a NetworkAgent, a
hardware abstraction layer, or firmware, beyond the application’s ordinary
socket send path.
A normal application can cross that boundary through the public Android-managed
IpSecManager.UdpEncapsulationSocket and ask
ConnectivityManager.createSocketKeepalive(...) to maintain a NAT-T mapping.
The framework routes the request through startNattKeepaliveWithFd(...),
accepts the duplicated fd and resource ID without proving current caller-owned
IpSec resource identity, and hands a completed NAT-T keepalive packet to the
Wi-Fi keepalive offload path without first enforcing the caller UID’s effective
VPN-lockdown policy. A controlled Pixel 8 Pro capture recorded the resulting
UDP/4500 packet on the physical access-point interface. Active-slot
observations on two additional OEMs exercised the same public
physical-gateway path on Qualcomm hardware
[8; 9; 10; 11; 12; 13; 14; 15; 16; 17].
Recent Android Automotive access-control work identified
ConnectivityService.startNattKeepaliveWithFd in a broad sweep of framework
permission anomalies because a related keepalive API enforced
PACKET_KEEPALIVE_OFFLOAD and the f