Description
On GrapheneOS, the system updater is explicitly designed to run before first unlock (BFU) so that critical security updates can be applied even while the device is locked. However, if Proton VPN’s kill-switch is enabled, it brings up the VPN interface before the user has unlocked the device, but the VPN service does not declare itself as Direct-Boot aware. As a result, no network is available in BFU, and the updater is unable to fetch updates. This effectively breaks GrapheneOS’s guaranteed-before-unlock update path, leaving devices unpatched until the next unlock—and potentially vulnerable.
Steps to reproduce:
Install Proton VPN on GrapheneOS (tested on Pixel 6 Pro running GrapheneOS 2025.05.15).
Enable the kill-switch in Proton VPN.
Reboot device.
Do not unlock the device; allow it to sit on the lock screen or idle.
Wait for the scheduled auto-update attempt.
Observe that the updater fails to download or apply any update because there is no network connectivity.
Expected behavior:
GrapheneOS auto-updater (which runs BFU) should be able to download updates over the network—even when the VPN kill-switch is on—because the VPN service itself is Direct-Boot aware and binds early in boot.
Actual behavior:
With kill-switch on, Proton VPN’s service does not start in the Direct-Boot (device-protected storage) context, so it never establishes any network. The system updater times out waiting for connectivity.
Security impact:
Because GrapheneOS’s updater is intended to apply security patches as early as possible during boot, any delay or failure to update can leave devices vulnerable to newly discovered exploits for longer periods. Ensuring Direct-Boot compatibility for the kill-switch VPN is critical to maintaining the OS’s threat-model guarantee.
Proposed fix:
In your AndroidManifest.xml, add android:directBootAware="true" to the VPN service and any components involved in establishing the kill-switch.
Migrate any necessary configuration and certificates to Device-Protected Storage (instead of credential-protected), so they’re accessible BFU.
Test on GrapheneOS and AOSP for BFU startup connectivity with kill-switch on.
Please let me know if you need any further logs or assistance debugging this—happy to help get it working!