Keepalive packets bypass Android lockdown
Android NAT-T keepalive offload egresses UDP/4500 below the VPN lockdown firewall, leaking the device's real IP outside the tunnel. Mechanism and detection.
Android’s VPN lockdown does not do what the setting name promises. “Always-on VPN” paired with “Block connections without VPN” is deployed as a kill switch: no packet leaves the device outside the tunnel. The NAT-T keepalive offload path breaks that guarantee. Keepalive packets for IPsec NAT traversal egress on the physical interface, below the firewall layer that lockdown depends on, carrying the device’s real source IP to an endpoint the VPN operator never sees. This is not a memory-corruption bug. It is a policy-enforcement bypass, and as of writing Google treats the behavior as designed rather than assigning it a corruption-class CVE.
Lockdown enforcement lives in netd. When an app calls VpnService.Builder with the LOCKDOWN flag, or an MDM pushes always-on VPN with the block-non-VPN option, netd installs firewall rules that confine egress to the tunnel. On current Android the enforcement is UID-based routing plus eBPF firewall programs (xt_qtaguid on older builds), evaluated in the netfilter output path. Every ordinary socket send is subject to those marks. Non-VPN egress is dropped. The VPN app’s own control sockets are the sanctioned exception. That is the entire enforcement model, and it holds for anything that traverses the application socket send path.
The NAT-T keepalive does not traverse that path. RFC 3948 UDP-encapsulated ESP requires a periodic keepalive to hold the NAT binding open: a single 0xFF byte on UDP/4500, sent at a profile-defined interval, commonly 20 seconds and configurable roughly 10 to 3600 seconds. Android exposes this through SocketKeepalive and IpSecManager (SocketKeepalive API since API 29, IpSec NAT-T keepalive infrastructure present earlier). To spare battery, the keepalive is offloaded. The kernel and, where the hardware supports it, the cellular modem or Wi-Fi firmware generate the packet on a timer without waking the application processor. Offload slots are limited (modems commonly expose three to four), which is why the platform reserves them for exactly this low-rate beacon.
The offload target is the underlying physical network, not the VPN’s virtual interface. That is the enforcement gap. The offloaded packet is emitted below the point where netd’s firewall marks are applied to application sockets. Lockdown never observes a socket send for it, because there is no application socket send. The packet leaves on rmnet0 or wlan0 with the physical interface’s real source IP, at the keepalive cadence, regardless of the block-non-VPN rule. The firewall is intact. The traffic simply never reaches it.
Two offload variants exist, and both bypass lockdown for the same structural reason. In the software variant the kernel’s UDP encapsulation socket generates the keepalive from kernel context, routed by the physical interface’s route entry rather than the VPN UID’s tunnel route. In the hardware variant the kernel programs the packet template, interval, and destination into the modem or Wi-Fi firmware over the HAL, and the radio emits it autonomously. Neither variant produces an application-context socket send on the VPN UID. The netfilter output hook and the eBPF firewall program that lockdown installs are evaluated against UID-tagged application sockets in that send path. A packet minted in kernel or radio context, addressed to the physical interface, does not pass through the check the way an app’s send does. The firewall is not bypassed by a flaw in its rules. It is bypassed because the traffic originates below the layer the rules police.
The attacker controls or observes the keepalive destination. If the IPsec peer address is attacker-adjacent, or sits on a path an attacker passively monitors, the 0xFF/UDP4500 beacon discloses the device’s real IP and its liveness cadence while the user believes every flow is tunneled. That defeats the geolocation and origin-concealment property the VPN was deployed to provide. The leak also survives tunnel churn: keepalives continue during IKE rekey and brief tunnel drops, which is precisely the window where a correlating observer wants a stable identifier. A device that goes dark inside the tunnel still emits the physical-interface beacon.
The correlation value does not require breaking cryptography. The ESP payload stays encrypted and the tunnel keys are never at risk. The observable is metadata: a stable real source IP, a fixed destination, and a periodic single-byte beacon whose interval is itself a fingerprint. A passive observer on hostile Wi-Fi, a carrier-position adversary, or a malicious IKEv2 responder can log the beacon and tie a real IP to a device across time and across networks where the keepalive endpoint stays constant. For a red team modeling deanonymization of a target who relies on always-on VPN for origin concealment, the offload beacon is the cheapest path to the real IP, and it needs no interaction with the device.
This is reconnaissance and collection, not code execution. Map it to T1590 for real-IP gathering, T1040 for capturing the beacon on the wire, and T1016 for the client-side network configuration it exposes. There is no privilege escalation and no host compromise. The value is deanonymization and metadata: which real IP, from which carrier or Wi-Fi network, alive on what schedule, correlatable across sessions where the keepalive endpoint is stable.
Public context sits alongside Mullvad’s audits of Android VPN behavior. Mullvad documented traffic leaking outside the tunnel with lockdown enabled, including connectivity checks and short leaks at connection setup, and Google’s response to several of those reports was that the behavior was intended. The NAT-T keepalive offload belongs in the same category: an OS-owned egress path that predates or sidesteps the lockdown firewall. Defenders should read the framing precisely. No patch-cycle fix is inbound for a behavior classified as working as designed. The exposure ships with the platform.
Severity does not translate cleanly to a memory-corruption CVSS vector, because there is no memory corruption. Characterized as an information-disclosure enforcement gap, the impact is confidentiality-only: network-adjacent vector, no privileges required, no user interaction beyond running an IPsec NAT-T tunnel under lockdown, scope limited to origin-IP and liveness metadata. That places it in the medium range in practical terms, and high for any user whose threat model is deanonymization. It is present wherever SocketKeepalive NAT-T offload and lockdown coexist, which spans Android 10 onward across the built-in IKEv2/IPsec client and IpSecManager-based apps. Older builds without eBPF firewalling exhibit the same gap through the legacy netfilter path.
Scope is specific. The leak affects IPsec and IKEv2 VPNs that use NAT traversal, which covers the Android built-in IKEv2/IPsec client and third-party clients built on IpSecManager. WireGuard and OpenVPN clients that implement their own application-layer keepalive are not affected by this offload path, because those keepalives are ordinary socket sends that ride inside the tunnel and are subject to the firewall. The distinction is the offload: a keepalive generated by kernel or modem hardware bypasses lockdown; a keepalive generated by an app socket does not. An enterprise that standardized on IKEv2/IPsec for always-on VPN carries the exposure; one on WireGuard largely does not.
On-device telemetry is close to nothing. Mobile EDR does not surface modem-generated keepalives, and the application processor may never wake for them, so there is no process event, no socket audit record, no on-device log tying the packet to a UID. The signal is on the wire. On the physical uplink, the leak is UDP/4500, payload length one, single byte 0xFF, source equal to the device’s real IP, periodic at the profile interval. On the VPN concentrator, the signal is absence: the tunnel endpoint never receives these packets, because they target the NAT-T peer over the physical path rather than inside ESP.
Network detection keys on that shape. Zeek logs UDP/4500 flows and preserves payload length, which is enough to isolate single-byte keepalives. A Suricata rule matching dsize:1 with content 0xFF on UDP/4500 from an asset that policy says must be fully tunneled flags the leak directly. The higher-confidence detection is a mismatch: a device under MDM-enforced always-on VPN that emits single-byte UDP/4500 beacons to any destination other than the sanctioned tunnel concentrator is not holding lockdown. Correlate observed keepalive destinations against the approved gateway list. Any delta is a policy failure, not a tuning artifact. False positives stay low because legitimate NAT-T keepalive to the real gateway is expected and whitelistable, leaving only the off-path beacons.
Detection engineering should join wire telemetry to asset context. Zeek conn logs or NetFlow give the UDP/4500 flows; the enrichment is the MDM inventory of devices under enforced always-on VPN. Any such device with UDP/4500 egress to a destination outside the approved concentrator list is leaking. The 20-second cadence is a usable secondary signal - a near-perfect periodic single-byte flow to one destination is a keepalive, not user traffic, and time-series regularity separates it from noise. The blind spots are worth stating plainly. An observer who only sees post-carrier-NAT traffic loses the pre-NAT real IP. A network segment where the physical link is itself encrypted below the observer’s tap yields nothing. And on-device tooling remains blind throughout, so a purely endpoint-based detection strategy will not catch this class at all. It is a network-visibility problem.
The residual reality after configuration is straightforward. Lockdown blocks application sockets. It does not block the NAT-T keepalive offload path, because the kernel or modem generates that traffic below the firewall. Post-hardening exposure is real source IP disclosure plus liveness beaconing to the keepalive endpoint, continuous, surviving rekey and short tunnel drops. The remediation is not a toggle in the VPN UI. Where the platform or client exposes control over keepalive offload, forcing the keepalive back onto the application socket path restores firewall coverage at a battery cost, because the application processor must wake to send it. Where that control is absent, the leak persists for the life of any IPsec NAT-T tunnel. Full-tunnel guarantees on Android are conditional. The condition is the offload path, and the offload path does not honor the kill switch.
Keep Reading
identity verificationThe session that never expired
How attackers held a year-long live feed inside an ID verification vendor via exposed credentials and session persistence, and why telemetry missed it.
session hijackingMFA protects the login, not the session.
Fastpotify mints unbound session cookies that survive MFA. Stolen via AiTM or infostealer, they replay as full sessions. The telemetry that catches it.
detection engineeringCount Binface breaks your correlation rule
Count Binface names a detection-pipeline attack: targeted noise injection exploits data-aggregation bias to bury true positives and poison UEBA baselines.
Stay in the loop
New writing delivered when it's ready. No schedule, no spam.