summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-06-28 16:04:15 +0900
committerOphestra <cat@gensokyo.uk>2025-06-28 16:04:15 +0900
commit0f310aa4501bef642fc67d5f8bada737a9611fd5 (patch)
tree24694166f5a75e0d32d59d7436fa7e49ce46381a
parentc6c9d6dea92b408faa2ecb3fba872de0724d6d27 (diff)
static: replace features with package
-rw-r--r--generate-sitemap.py2
-rw-r--r--static/features.html1526
-rw-r--r--static/package.html52
-rw-r--r--templates/header.html2
4 files changed, 54 insertions, 1528 deletions
diff --git a/generate-sitemap.py b/generate-sitemap.py
index 1f5c9fe7..e35f5e64 100644
--- a/generate-sitemap.py
+++ b/generate-sitemap.py
@@ -11,7 +11,7 @@ pages = [
["/camera-privacy-policy", 0.0],
["/contact", 0.5],
["/faq", 1.0],
- ["/features", 1.0],
+ ["/package", 1.0],
["/hiring", 0.2],
["/humans.txt", 0.0],
["/pdfviewer-privacy-policy", 0.0],
diff --git a/static/features.html b/static/features.html
deleted file mode 100644
index 019f0aa7..00000000
--- a/static/features.html
+++ /dev/null
@@ -1,1526 +0,0 @@
-<!DOCTYPE html>
-<html lang="en" prefix="og: https://ogp.me/ns#">
- <head>
- <meta charset="utf-8"/>
- <title>Features overview | GrapheneOS</title>
- <meta name="description" content="Overview of GrapheneOS features differentiating it from the Android Open Source Project (AOSP)."/>
- <meta name="theme-color" content="#212121"/>
- <meta name="color-scheme" content="dark light"/>
- <meta name="msapplication-TileColor" content="#ffffff"/>
- <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"/>
- <meta name="twitter:site" content="@GrapheneOS"/>
- <meta name="twitter:creator" content="@GrapheneOS"/>
- <meta property="og:title" content="GrapheneOS features overview"/>
- <meta property="og:description" content="Overview of GrapheneOS features differentiating it from the Android Open Source Project (AOSP)."/>
- <meta property="og:type" content="website"/>
- <meta property="og:image" content="https://grapheneos.org/opengraph.png"/>
- <meta property="og:image:width" content="512"/>
- <meta property="og:image:height" content="512"/>
- <meta property="og:image:alt" content="GrapheneOS logo"/>
- <meta property="og:site_name" content="GrapheneOS"/>
- <meta property="og:url" content="https://grapheneos.org/features"/>
- <link rel="canonical" href="https://grapheneos.org/features"/>
- <link rel="icon" href="/favicon.ico"/>
- <link rel="icon" sizes="any" type="image/svg+xml" href="/favicon.svg"/>
- <link rel="mask-icon" href="[[path|/mask-icon.svg]]" color="#1a1a1a"/>
- <link rel="apple-touch-icon" href="/apple-touch-icon.png"/>
- [[css|/main.css]]
- <link rel="manifest" href="/manifest.webmanifest"/>
- <link rel="license" href="/LICENSE.txt"/>
- <link rel="me" href="https://grapheneos.social/@GrapheneOS"/>
- [[js|/js/redirect.js]]
- </head>
- <body>
- {% with current_page="features" %}
- {% include "header.html" %}
- {% endwith %}
- <main id="features">
- <h1><a href="#features">Features overview</a></h1>
-
- <p>GrapheneOS is a private and secure mobile operating system with great functionality
- and usability. It starts from the strong baseline of the
- <a href="https://source.android.com/">Android Open Source Project (AOSP)</a> and
- takes great care to avoid increasing attack surface or hurting the strong security
- model. GrapheneOS makes substantial improvements to both privacy and security through
- many carefully designed features built to function against real adversaries. The
- project cares a lot about usability and app compatibility so those are taken into
- account for all of our features.</p>
-
- <p>GrapheneOS is focused on substance rather than branding and marketing. It doesn't
- take the typical approach of piling on a bunch of insecure features depending on the
- adversaries not knowing about them and regressing actual privacy/security. It's a very
- technical project building privacy and security into the OS rather than including
- assorted unhelpful frills or bundling subjective third party apps choices.</p>
-
- <p>GrapheneOS is also hard at work on filling in gaps from not bundling Google apps
- and services into the OS. We aren't against users using Google services but it doesn't
- belong integrated into the OS in an invasive way. GrapheneOS won't take the shortcut
- of simply bundling a very incomplete and poorly secured third party reimplementation
- of Google services into the OS. That wouldn't ever be something users could rely upon.
- It will also always be chasing a moving target while offering poorer security than the
- real thing if the focus is on simply getting things working without great care for
- doing it robustly and securely.</p>
-
- <p>This page provides an overview of currently implemented features differentiating
- GrapheneOS from AOSP. It doesn't document our many historical features that are no
- longer included for one reason or another. Many of our features were implemented in
- AOSP, Linux, <a href="https://llvm.org/">LLVM</a> and other projects GrapheneOS is
- based on and those aren't listed here. In many cases, we've been involved in getting
- those features implemented in core infrastructure projects.</p>
-
- <nav id="table-of-contents">
- <h2><a href="#table-of-contents">Table of contents</a></h2>
-
- <ul>
- <li>
- <a href="#grapheneos">GrapheneOS</a>
- <ul>
- <li>
- <a href="#exploit-protection">Defending against exploitation of
- unknown vulnerabilities</a>
- <ul>
- <li><a href="#attack-surface-reduction">Attack surface
- reduction</a>
- <ul>
- <li><a href="#usb-c-port-and-pogo-pins-control">USB-C port and pogo pins control</a></li>
- </ul>
- </li>
- <li><a href="#exploit-mitigations">Exploit
- mitigations</a></li>
- <li><a href="#improved-sandboxing">Improved
- sandboxing</a></li>
- <li><a href="#anti-persistence">Anti-persistence /
- detection</a></li>
- </ul>
- </li>
- <li><a href="#more-complete-patching">More complete patching</a></li>
- <li><a href="#sandboxed-google-play">Sandboxed Google Play</a></li>
- <li><a href="#android-auto">Android Auto</a></li>
- <li><a href="#network-permission-toggle">Network permission toggle</a></li>
- <li><a href="#sensors-permission-toggle">Sensors permission toggle</a></li>
- <li><a href="#storage-scopes">Storage Scopes</a></li>
- <li><a href="#contact-scopes">Contact Scopes</a></li>
- <li><a href="#broad-carrier-support">Broad carrier support without invasive carrier access</a></li>
- <li><a href="#lte-only-mode">LTE-only mode</a></li>
- <li><a href="#wifi-privacy">Wi-Fi privacy</a></li>
- <li><a href="#network-location">Network location</a></li>
- <li><a href="#private-screenshots">Private screenshots</a></li>
- <li><a href="#closed-device-identifier-leaks">Closed device identifier leaks</a></li>
- <li><a href="#privacy-by-default">Privacy by default</a></li>
- <li><a href="#pin-scrambling">PIN scrambling</a></li>
- <li><a href="#two-factor-fingerprint-unlock">Two-factor fingerprint unlock</a></li>
- <li><a href="#supports-longer-passwords">Supports longer
- passwords</a></li>
- <li><a href="#auto-reboot">Auto reboot</a></li>
- <li><a href="#clearing-sensitive-data-from-memory">Clearing sensitive data from memory</a></li>
- <li><a href="#duress">Duress PIN/Password</a></li>
- <li><a href="#more-secure-fingerprint-unlock">More secure fingerprint
- unlock</a></li>
- <li>
- <a href="#improved-user-profiles">Improved user profiles</a>
- <ul>
- <li><a href="#more-user-profiles">More user profiles</a></li>
- <li><a href="#end-session">End session</a></li>
- <li><a href="#disabling-app-installation">Disabling app installation</a></li>
- <li><a href="#install-available-apps">Install available apps</a></li>
- <li><a href="#notification-forwarding">Notification forwarding</a></li>
- </ul>
- </li>
- <li><a href="#grapheneos-app-repository">GrapheneOS app
- repository</a></li>
- <li><a href="#vanadium">Vanadium: hardened WebView and default
- browser</a></li>
- <li><a href="#auditor">Auditor app and attestation service</a></li>
- <li><a href="#grapheneos-camera">GrapheneOS Camera</a></li>
- <li><a href="#grapheneos-pdf-viewer">GrapheneOS PDF Viewer</a></li>
- <li><a href="#setup-wizard">GrapheneOS Setup Wizard</a></li>
- <li><a href="#encrypted-backups">Encrypted backups</a></li>
- <li><a href="#location-data-access-indicator">Location data access
- indicator</a></li>
- <li><a href="#user-installed-apps-can-be-disabled">User installed apps
- can be disabled</a></li>
- <li><a href="#improved-vpn-leak-blocking">Improved VPN leak blocking</a></li>
- <li><a href="#log-viewer-and-crash-reporting">Log viewer and user-facing crash reporting</a></li>
- <li><a href="#other-features">Other features</a></li>
- </ul>
- </li>
- <li><a href="#services">Services</a></li>
- <li><a href="#project">Project</a></li>
- </ul>
- </nav>
-
- <section id="grapheneos">
- <h2><a href="#grapheneos">GrapheneOS</a></h2>
-
- <p>These are the features of GrapheneOS beyond what's provided by version 15 of
- the Android Open Source Project. It only covers our improvements to AOSP and not
- baseline features. This section doesn't list features like the standard app
- sandbox, verified boot, exploit mitigations (ASLR, SSP, Shadow Call Stack, Control
- Flow Integrity, etc.), permission system (foreground-only and one-time permission
- grants, scoped file access control, etc.) and so on but rather only our
- improvements to modern Android. We plan on providing a separate page listing the
- improvements we've contributed to Android since those features aren't listed here
- despite being a substantial portion of our overall historical work.</p>
-
- <section id="exploit-protection">
- <h3><a href="#exploit-protection">Defending against exploitation of unknown
- vulnerabilities</a></h3>
-
- <p>GrapheneOS is heavily focused on protecting users against attackers
- exploiting unknown (0 day) vulnerabilities. Patching vulnerabilities doesn't
- protect users before the vulnerability is known to the vendor and has a patch
- developed and shipped.</p>
-
- <p>Unknown (0 day) vulnerabilities are much more widely used than most realize
- to exploit users not just in targeted attacks but in broad deployments.
- Project Zero maintains
- <a href="https://docs.google.com/spreadsheets/d/1lkNJ0uQwbeC1ZTRrxdtuPLCIl7mlUreoKfSIgajnSyY/view#gid=0">a
- spreadsheet</a> tracking zero day exploitation detected in the wild. This is
- only a peek into what's happening since it only documents cases where the
- attackers were caught exploiting users, often because the attacks are not
- targeted but rather deployed on public websites, etc.</p>
-
- <p>The first line of defense is attack surface reduction. Removing unnecessary
- code or exposed attack surface eliminates many vulnerabilities completely.
- GrapheneOS avoids removing any useful functionality for end users, but we can
- still disable lots of functionality by default and require that users opt-in
- to using it to eliminate it for most of them. An example we landed upstream in
- Android is disallowing using the kernel's profiling support by default, since
- it was and still is a major source of Linux kernel vulnerabilities. Profiling
- is now only exposed to apps for developers who enable developer tools, enable
- the Android Debug Bridge (ADB) and then use profiling tools via ADB. It's also
- only enabled until the next boot. This isn't listed below since it's one of
- the features we got implemented in Android itself.</p>
-
- <p>The next line of defense is preventing an attacker from exploiting a
- vulnerability, either by making it impossible, unreliable or at least
- meaningfully harder to develop. The vast majority of vulnerabilities are well
- understood classes of bugs and exploitation can be prevented by avoiding the
- bugs via languages/tooling or preventing exploitation with strong exploit
- mitigations. In many cases, vulnerability classes can be completely wiped out
- while in many others they can at least be made meaningfully harder to exploit.
- Android does a lot of work in this area, and GrapheneOS has helped to advance
- this in Android and the Linux kernel. It takes an enormous amount of resources
- to develop fundamental fixes for these problems and there's often a high
- performance, memory or compatibility cost to deploying them. Mainstream
- operating systems usually don't prioritize security over other areas.
- GrapheneOS is willing to go further, thus we offer toggles for users to choose
- the compromises they prefer instead of forcing it on them. In the meantime,
- weaker less complete exploit mitigations can still provide meaningful barriers
- against attacks as long as they're developed with a clear threat model.
- GrapheneOS is heavily invested in many areas of developing these protections:
- developing/deploying memory safe languages/libraries, static/dynamic
- analysis tooling and many kinds of mitigations.</p>
-
- <p>The final line of defense is containment through sandboxing at various
- levels: fine-grained sandboxes around a specific context like per site browser
- renderers, sandboxes around a specific component like Android's media codec
- sandbox and app/workspace sandboxes like the Android app sandbox used to
- sandbox each app which is also the basis for user/work profiles. GrapheneOS
- improves all of these sandboxes through fortifying the kernel and other base
- OS components along with improving the sandboxing policies.</p>
-
- <p>Preventing an attacker from persisting their control of a component or the
- OS/firmware through verified boot and avoiding trust in persistent state
- also helps to mitigate the damage after a compromise has occurred.</p>
-
- <p>Remote code execution vulnerabilities are the most serious and allow an
- attacker to gain a foothold on the device or even substantial control over it
- remotely. Local code execution vulnerabilities allow breaking out of a sandbox
- including the app sandbox or browser renderer sandbox after either
- compromising an app/browser renderer remotely, compromising an app's supply
- chain or getting the user to install a malicious app. Many other kinds of
- vulnerabilities exist but most of what we're protecting against falls into
- these two broad categories.</p>
-
- <p>The vast majority of local and remote code execution vulnerabilities are
- memory corruption bugs caused by memory unsafe languages or rare low-level
- unsafe code in an otherwise memory safe language. Most of the remaining issues
- are caused by dynamic code execution/loading features. Our main focus is on
- preventing or raising the difficulty of exploiting memory corruption bugs
- followed by restricting dynamic code execution both to make escalation from a
- memory corruption bug harder and to directly mitigate bugs caused by dynamic
- code loading/generation/execution such as a JIT compiler bug or a plugin
- loading vulnerability.</p>
-
- <section id="attack-surface-reduction">
- <h4><a href="#attack-surface-reduction">Attack surface reduction</a></h4>
-
- <ul>
- <li>Greatly reduced remote, local and proximity-based attack surface by
- stripping out unnecessary code, making more features optional and
- disabling optional features by default (NFC, Bluetooth, UWB, etc.), when
- the screen is locked (USB, USB-C, pogo pins, camera access) and optionally
- after a timeout (Bluetooth, Wi-Fi).</li>
- <li>Native debugging (ptrace) access is blocked for all bundled apps to
- reduce local attack surface. ptrace access is allowed by default for user
- installed apps for compatibility, with an option to block it by default. In
- both cases, ptrace access can be blocked or allowed manually on a per-app
- basis. When an app that is blocked from accessing ptrace tries to use it,
- GrapheneOS shows a notification that links the per-app native debugging
- settings screen.</li>
- </ul>
-
- <h5 id="usb-c-port-and-pogo-pins-control"><a href="#usb-c-port-and-pogo-pins-control">USB-C port and pogo pins control</a></h5>
-
- <p>Our <b>USB-C port and pogo pins</b> setting protects against attacks
- through USB-C or pogo pins while the OS is booted. For the majority of
- devices without pogo pins, the setting is labelled <b>USB-C port</b>.</p>
-
- <p>The feature has five modes:</p>
-
- <ul>
- <li>Off</li>
- <li>Charging-only</li>
- <li>Charging-only when locked</li>
- <li>Charging-only when locked, except before first unlock</li>
- <li>On</li>
- </ul>
-
- <p>The default is <b>Charging-only when locked</b>, which significantly
- reduces attack surface when the device is locked. After locking, it blocks
- any new USB connections immediately through either USB-C and pogo pins at
- both the hardware level via configuring the USB controller and also at the
- OS level in the kernel to provide a second layer of defense. It disables the
- data lines at a hardware level as soon as the existing connections end which
- happens right away if there were no USB connections. It also disables USB-C
- alternate modes including DisplayPort at both the OS and hardware level.</p>
-
- <p>Our implementation is far more secure than Android's standard USB HAL
- toggle available to device admin apps. The standard feature only disables
- high level USB handling in the OS. It doesn't block new USB connections or
- disable the data lines at a hardware level. It also leaves the handling of
- the USB-C and pogo pins protocols enabled in the OS, and it doesn't disable
- the USB-C alternate modes. The standard feature is also either blocking or
- not blocking USB at a high level, without the ability to block new
- connections and disable USB only once the existing connections end. Other
- operating systems trying to implement a similar feature via the standard
- toggle end up continuing to allow new USB connections in the OS until all
- connections end instead of the two-phase approach we use for our two
- Charging-only when locked modes.</p>
-
- <p>The highest security <b>Off</b> mode disables charging in addition to
- data to remove the remaining attack surface from the USB controller and OS
- supporting charging including the USB-PD protocol. There's no risk of the
- device not being able to be charged since the overall feature doesn't apply
- while the device is powered off, booted into the firmware-based fastboot
- mode or the charging, recovery and fastbootd modes.</p>
- </section>
-
- <section id="exploit-mitigations">
- <h4><a href="#exploit-mitigations">Exploit mitigations</a></h4>
-
- <ul>
- <li>Hardened app runtime</li>
- <li><a href="/usage#exec-spawning">Secure application spawning
- system</a> avoiding sharing address space layout and other secrets
- across applications</li>
- <li><a href="https://github.com/GrapheneOS/platform_bionic">Hardened libc</a>
- providing defenses against the most common classes of vulnerabilities (memory
- corruption)</li>
- <li>
- Our own <a href="https://github.com/GrapheneOS/hardened_malloc">hardened
- malloc (memory allocator)</a> leveraging modern hardware capabilities
- to provide substantial defenses against the most common classes of
- vulnerabilities (heap memory corruption) along with reducing the lifetime
- of sensitive data in memory. The <a
- href="https://github.com/GrapheneOS/hardened_malloc/blob/main/README.md">hardened_malloc
- README</a> has extensive documentation on it. The hardened_malloc
- project is portable to other Linux-based operating systems and is being
- adopted by other security-focused operating systems like secureblue. Our
- allocator also heavily influenced the design of the <a
- href="https://www.openwall.com/lists/musl/2020/05/13/1">next-generation
- musl malloc implementation</a> which offers substantially better security than
- musl's previous malloc while still having minimal memory usage and code size.
- <ul>
- <li>Fully out-of-line metadata with protection from corruption, ruling
- out traditional allocator exploitation</li>
- <li>Separate memory regions for metadata, large allocations and each
- slab allocation size class with high entropy random bases and no
- address space reuse between the different regions</li>
- <li>Deterministic detection of any invalid free</li>
- <li>Zero-on-free with detection of write-after-free via checking that
- memory is still zeroed before handing it out again</li>
- <li>Delayed reuse of address space and memory allocations through the
- combination of deterministic and randomized quarantines to mitigate
- use-after-free vulnerabilities</li>
- <li>Fine-grained randomization</li>
- <li>Aggressive consistency checks</li>
- <li>Memory protected guard regions around allocations larger than 16k
- with randomization of guard region sizes for 128k and above</li>
- <li>Allocations smaller than 16k have guard regions around each of the
- slabs containing allocations (for example, 16 byte allocations are in
- 4096 byte slabs with 4096 byte guard regions before and after)</li>
- <li>Random canaries with a leading zero are added to these smaller
- allocations to block C string overflows, absorb small overflows
- and detect linear overflows or other heap corruption when the
- canary value is checked (primarily on free)</li>
- <li>Hardware memory tagging for slab allocations (128k and
- below) providing probabilistic detection of all use-after-free
- and inter-object overflows along with deterministic detection
- of all small/linear overflows and use-after-free until it has
- been reused once and gone through the quarantines twice</li>
- </ul>
- </li>
- <li>On ARMv9, Branch Target Identification (BTI) and Pointer
- Authentication Code (PAC) return address protection are enabled for
- userspace OS code we build instead of only specific apps</li>
- <li>Signed integer overflow is made well defined in C and C++ for code
- where automatic overflow checking is disabled</li>
- <li>
- Hardened kernel
- <ul>
- <li>4-level page tables are enabled on arm64 to provide a much
- larger address space (48-bit instead of 39-bit) with
- significantly higher entropy Address Space Layout
- Randomization (33-bit instead of 24-bit).</li>
- <li>Basic hardware memory tagging is used in the main kernel
- memory allocators (slab, page_alloc, non-executable vmalloc) to
- provide probabilistic detection of all use-after-free and
- inter-object overflows along with deterministic detection of
- use-after-free until the memory is allocated again (we plan to
- add deterministic detection of small/linear overflows like
- hardened_malloc)</li>
- <li>Random canaries with a leading zero are added to the
- kernel heap (slub) to block C string overflows, absorb small
- overflows and detect linear overflows or other heap corruption
- when the canary value is checked (on free, copies to/from
- userspace, etc.).</li>
- <li>Memory is wiped (zeroed) as soon as it's released in both
- the low-level kernel page allocator and higher level kernel
- heap allocator (slub). This substantially reduces the lifetime
- of sensitive data in memory, mitigates use-after-free
- vulnerabilities and makes most uninitialized data usage
- vulnerabilities harmless. Without our changes, memory that's
- released retains data indefinitely until the memory is handed
- out for other uses and gets partially or fully overwritten by
- new data.</li>
- <li>In early boot, all the memory not being used by the OS is
- zeroed to get rid of any data leftover from a previous boot in
- case zero-on-free didn't have the opportunity to clear it as
- part of a clean reboot/shutdown. All the devices we support have
- a reset attack protection feature we proposed zeroing memory for
- firmware-based boot modes, but we need to finish it up by adding
- it for the OS boot modes ourselves. Fully encrypted RAM with a
- per-boot key cycled on reboots will eventually obsolete these
- features for newer devices.</li>
- <li>Kernel stack allocations are zeroed to make most
- uninitialized data usage vulnerabilities harmless.</li>
- <li>Assorted attack surface reduction through disabling
- features or setting up infrastructure to dynamically
- enable/disable them only as needed (perf, ptrace).</li>
- <li>Assorted upstream hardening features are enabled,
- including many which we played a part in developing and
- landing upstream as part of our linux-hardened project (which
- we intend to revive as a more active project again).</li>
- <li>Forced kernel module signing with per-build RSA 4096 /
- SHA256 keys and lockdown mode set to forced confidentiality
- mode help to enforce a low-level boundary between the kernel
- and userspace even if mistakes are made in SELinux policy or
- there's a deep userspace compromise.</li>
- <li>Additional consistency/integrity checks are enabled for
- frequently targeted kernel data structures.</li>
- <li>On ARMv9, Branch Target Identification (BTI) is enabled in
- addition to Clang type-based Control Flow Integrity (CFI) to
- cover functions excluded from type-based CFI</li>
- <li>On ARMv9, ShadowCallStack (SCS) is enabled in addition to
- Pointer Authentication Code (PAC) return address protection
- instead of only enabling SCS when PAC is unavailable</li>
- </ul>
- </li>
- <li>Android Runtime Just-In-Time (JIT) compilation/profiling is fully
- disabled and replaced with full ahead-of-time (AOT) compilation. The
- only JIT compilation in the base OS is the V8 JavaScript JIT which is
- disabled by default for the Vanadium browser with per-site exception
- support.</li>
- <li>Dynamic code loading for both native code or Java/Kotlin classes is
- blocked for nearly the entire base OS to prevent base OS processes. This
- works alongside verified boot to prevent base OS processes from running
- attacker controlled native code or Java/Kotlin code. The only exceptions
- from the policy for the base OS are in-memory code loading for the media
- DRM sandbox and the Vanadium JIT compiler being permitted. Vanadium has
- JIT compilation disabled by default for every site and for apps using
- the WebView with the exception of our PDF Viewer app. Vanadium disables
- the JIT compiler by default with a per-site and per-app toggle for it
- and per-process enforcement of blocking dynamic code loading implemented
- with seccomp-bpf based on the per-site/per-app JIT compiler toggle.</li>
- <li>Dynamic code loading for both native code or Java/Kotlin classes can
- be disabled for user installed apps via 3 exploit protection toggles:
- Dynamic code loading from memory, Dynamic code loading from storage and
- WebView JIT. This can also be used to opt-out of the WebView JIT for our
- PDF Viewer and dynamic code loading from memory for the Vanadium browser
- to disable support for the per-site opt-in to JIT compilation. In order
- to make the dynamic code loading toggles more usable, we show a user
- facing notification when an app has dynamic code loading from memory or
- storage blocked, including a file path being shown when it's blocked
- from storage. This allows users to disable it for all their apps and
- then enable them for the ones requiring it.</li>
- <li>Filesystem access hardening</li>
- </ul>
- </section>
-
- <section id="improved-sandboxing">
- <h4><a href="#improved-sandboxing">Improved sandboxing</a></h4>
-
- <p>GrapheneOS improves the app sandbox through hardening SELinux policy
- and seccomp-bpf policy along with all the hardening to components like
- kernel implementing the app sandbox and providing a path for the attacker
- to escape it if they can exploit those components. We primarily focus on
- the app sandbox, but we also improve the other sandboxes including making
- direct improvements to the web browser renderer sandbox used for both the
- default browser and WebView rendering engine provided by the OS and used
- by a huge number of other apps from dedicated browsers to messaging
- apps.</p>
- </section>
-
- <section id="anti-persistence">
- <h4><a href="#anti-persistence">Anti-persistence / detection</a></h4>
-
- <ul>
- <li>Enhanced <a href="https://source.android.com/docs/security/features/verifiedboot">verified boot</a>
- with better security properties and reduced attack surface</li>
- <li>GrapheneOS finishes the incomplete implementation of verified boot
- for out-of-band updates to packages (APKs) in the OS. We enforce this
- by requiring fs-verity metadata signed with a trusted key for system
- app updates both at install time and boot time. This provides
- continuous verification where every read from an out-of-band APK
- update is verified similarly to every read from a firmware, OS image
- or APEX update being verified. The signing key and version are
- enforced to prevent downgrades or other attacks such as replacing a
- package with a variant of the same one from a different GrapheneOS
- supported device. We disable the persistent package parsing cache to
- prevent bypassing the metadata checks through this otherwise highly
- persistent state, which only has a very small negative impact on boot
- time from the data not being available from previous boots (typically
- less than 1 second).</li>
- <li>GrapheneOS closes a loophole where app-based system components
- built as part of the OS can be downgraded to an older version due to
- versionCode not being incremented when system components get updated
- as part of changes to the OS. We enforce this both at package install
- time and boot time.</li>
- <li>Enhanced hardware-based attestation with more precise version information</li>
- <li>Hardware-based security verification and monitoring via our
- <a href="#auditor">Auditor app and attestation service</a></li>
- <li>Compressed APEX module support is disabled as it's not useful for GrapheneOS,
- uses extra unnecessary storage space and adds more verified boot attack surface.</li>
- </ul>
- </section>
- </section>
-
- <section id="more-complete-patching">
- <h3><a href="#more-complete-patching">More complete patching</a></h3>
-
- <p>GrapheneOS includes fixes for a large number of vulnerabilities not yet
- fixed in Android.</p>
-
- <p>We're able to quickly and safely ship the latest Linux kernel LTS point
- releases on devices with GKI (Generic Kernel Image) support including the 6th
- and 7th generation Pixel phones. At the time of writing on 2023-11-06,
- GrapheneOS is using the latest Linux 5.10 GKI LTS release (5.10.199) for 6th
- and 7th generation Pixel phones. The stock Pixel OS is on Linux 5.10.157 from
- 2022-12-02 with a small number of additional patches backported. This means
- GrapheneOS provides hundreds of relevant kernel patches including many
- security patches not yet included in the stock OS. It's possible for us to
- stay several months ahead due to their approach of moving to new LTS releases
- only in quarterly releases after a long freeze and testing process.</p>
-
- <p>We often find new vulnerabilities ourselves and report them upstream. We've
- reported dozens of vulnerabilities for both the generic Android codebase and
- also for Pixels specifically. We also often find missed patches which were
- supposed to be included but were missed, especially when there are device
- specific components with partially shared but separate codebases for different
- devices.</p>
-
- <p>Our overall approach is to focus on systemic privacy and security
- improvements but fixing individual vulnerabilities is still very
- important.</p>
- </section>
-
- <section id="sandboxed-google-play">
- <h3><a href="#sandboxed-google-play">Sandboxed Google Play</a></h3>
-
- <p>GrapheneOS has a compatibility layer providing the option to install and use
- the official releases of Google Play in the standard app sandbox. Google Play
- receives absolutely no special access or privileges on GrapheneOS as opposed to
- bypassing the app sandbox and receiving a massive amount of highly privileged
- access. Instead, the compatibility layer teaches it how to work within the full
- app sandbox. It also isn't used as a backend for the OS services as it would be
- elsewhere since GrapheneOS doesn't use Google Play even when it's installed.</p>
-
- <p>Since the Google Play apps are simply regular apps on GrapheneOS, you install
- them within a specific user or work profile and they're only available within that
- profile. Only apps within the same profile can use it, and they need to explicitly
- choose to use it. It works the same way as any other app and has no special
- capabilities. As with any other app, it can't access data of other apps and
- requires explicit user consent to gain access to profile data or the standard
- permissions. Apps within the same profile can communicate with mutual consent and
- it's no different for sandboxed Google Play.</p>
-
- <p>Sandboxed Google Play is close to being fully functional and provides near
- complete compatibility with the app ecosystem depending on Google Play. Only a
- small subset of privileged functionality which we haven't yet ported to
- different approaches with our compatibility layer is unavailable. Some
- functionality is inherently privileged and can't be provided as part of the
- compatibility layer.</p>
-
- <p>The vast majority of Play services functionality works perfectly including
- dynamically downloaded/updated modules (dynamite modules) and functionality
- provided by modular app components such as Google Play Games. By default,
- location requests are rerouted to a reimplementation of the Play geolocation
- service provided by GrapheneOS. You can disable rerouting and use the standard
- Play services geolocation service instead if you want the Google network
- location service and related features.</p>
-
- <p>Our compatibility layer includes full support for the Play Store. Play
- Store services are fully available including in-app purchases, Play Asset
- Delivery, Play Feature Delivery and app/content license checks. It can
- install, update and uninstall apps with the standard approach requiring that
- the user authorizes it as an app source and consents to each action. It will
- use the standard Android 12+ unattended update feature to do automatic updates
- for apps where it was the last installer.</p>
-
- <p>See the <a href="/usage#sandboxed-google-play-installation">usage guide
- section on sandboxed Google Play</a> for instructions.</p>
- </section>
-
- <section id="android-auto">
- <h3><a href="#android-auto">Android Auto</a></h3>
-
- <p>GrapheneOS provides an option to install and use the official releases of
- Android Auto.</p>
-
- <p>Android Auto requires privileged access in order to work. GrapheneOS uses
- an extension of the sandboxed Google Play compatibility layer to make Android
- Auto work with a reduced level of privileges.</p>
-
- <p>For more details, see the <a href="/usage#android-auto">usage guide section
- on Android Auto</a>.</p>
- </section>
-
- <section id="network-permission-toggle">
- <h3><a href="#network-permission-toggle">Network permission toggle</a></h3>
-
- <p>GrapheneOS adds a Network permission toggle for disallowing both direct and
- indirect access to any of the available networks. The device-local network
- (localhost) is also guarded by this permission, which is important for
- preventing apps from using it to communicate between profiles. Unlike a
- firewall-based implementation, the Network permission toggle prevents apps
- from using the network via APIs provided by the OS or other apps in the same
- profile as long as they're marked appropriately.</p>
-
- <p>The standard INTERNET permission used as the basis for the Network
- permission toggle is enhanced with a second layer of enforcement and proper
- support for granting/revoking it on a per-profile basis.</p>
-
- <p>To avoid breaking compatibility with Android apps, the added permission
- toggle is enabled by default. However, the OS app installation UI has been
- extended to show the toggle as part of the installation confirmation page so
- users can disable it when installing an app.</p>
-
- <p>When the Network permission is disabled, GrapheneOS pretends the network is
- down. It shows the network as down in various APIs, returns errors showing a
- network connectivity issue rather than a revoked permission and avoids running
- scheduled jobs depending on the network. This results in apps handling it as
- if the network is down rather than crashing or showing errors from trying to
- use the network and being unable to do it.</p>
- </section>
-
- <section id="sensors-permission-toggle">
- <h3><a href="#sensors-permission-toggle">Sensors permission toggle</a></h3>
-
- <p>Sensors permission toggle: disallow access to all other sensors not covered
- by existing Android permissions (Camera, Microphone, Body Sensors, Activity
- Recognition) including an accelerometer, gyroscope, compass, barometer,
- thermometer and any other sensors present on a given device. When access is
- disabled, apps receive zeroed data when they check for sensor values and don't
- receive events. GrapheneOS creates an easy-to-disable notification when apps
- try to access sensors blocked by the permission being denied. This makes the
- feature more usable since users can tell if the app is trying to access this
- functionality.</p>
-
- <p>To avoid breaking compatibility with Android apps, the added permission is
- enabled by default. When an app attempts to access sensors and receives zeroed
- data due to being denied, GrapheneOS creates a notification that can be
- easily disabled. The Sensors permission can be set to be disabled by default
- for user installed apps in <b>Settings&#160;<span aria-label="and then">></span>
- Security &amp; privacy&#160;<span aria-label="and then">></span>
- More security &amp; privacy</b>.</p>
- </section>
-
- <section id="storage-scopes">
- <h3><a href="#storage-scopes">Storage Scopes</a></h3>
-
- <p>GrapheneOS provides Storage Scopes as a fully compatible alternative to the
- standard Android storage permissions. Instead of granting storage permissions,
- users can enable Storage Scopes to make the app assume that it has all storage
- permissions that it asked for. On Android, an app that doesn't have any storage
- permissions is still allowed to create files and directories, and is allowed to
- access the files that it created. Users can optionally add files and directories
- as storage scopes to permit the app to access files created by other apps.</p>
-
- <p>For more details, see the <a href="/usage#storage-access">usage guide
- section on storage access</a>.</p>
- </section>
-
- <section id="contact-scopes">
- <h3><a href="#contact-scopes">Contact Scopes</a></h3>
-
- <p>GrapheneOS provides Contact Scopes as an alternative to granting the
- Contacts permission. By default, it acts as if the contacts list is empty and
- users can grant different kinds of access to specific contacts or groups of
- contacts.</p>
-
- <p>For more details, see the <a href="/usage#contact-scopes">usage guide section
- on Contact Scopes</a>.</p>
- </section>
-
- <section id="broad-carrier-support">
- <h3><a href="#broad-carrier-support">Broad carrier support without invasive carrier access</a></h3>
-
- <p>GrapheneOS has much broader carrier support than AOSP and mostly matches
- the stock OS on Pixels without making the same sacrifices. We convert their
- APN, carrier configuration, MMS and visual voicemail databases to the formats
- used by AOSP with our CarrierConfig2 project and scripts. We strip out
- anti-user configuration requiring provisioning for tethering, forbidding
- disabling 2G, etc. We don't include the invasive carrier-specific apps and
- support for Open Mobile Alliance Device Management (OMA DM) so we also strip
- out configuration depending on those.</p>
-
- <p>See our <a href="/usage#carrier-functionality">usage guide section on
- carrier functionality</a> for more details.</p>
- </section>
-
- <section id="lte-only-mode">
- <h3><a href="#lte-only-mode">LTE-only mode</a></h3>
-
- <p><a href="/usage#lte-only-mode">LTE-only mode</a> to reduce cellular radio
- attack surface by disabling enormous amounts of both legacy code (2G, 3G) and
- bleeding edge code (5G).</p>
- </section>
-
- <section id="wifi-privacy">
- <h3><a href="#wifi-privacy">Wi-Fi privacy</a></h3>
-
- <p>GrapheneOS supports per-connection MAC randomization and enables it by
- default. This is a more private approach than the standard persistent
- per-network random MAC used by modern Android.</p>
-
- <p>When the per-connection MAC randomization added by GrapheneOS is being
- used, DHCP client state is flushed before reconnecting to a network to avoid
- revealing that it's likely the same device as before.</p>
-
- <p>GrapheneOS also applies fixes for serious flaws with the Linux kernel IPv6
- privacy address implementation which allow using it as an identifier not just
- for connections to the same network but also across different networks. We
- don't need to apply these changes for the Pixel 6 and later since this was
- fixed in the Linux kernel upstream, but hasn't been backported to earlier
- kernel LTS branches so we still need to take care of it there.</p>
-
- <p>See our <a href="/usage#wifi-privacy">usage guide section on Wi-Fi privacy
- for more general information</a> rather than only our improvements to the
- standard Wi-Fi privacy approach.</p>
- </section>
-
- <section id="network-location">
- <h3><a href="#network-location">Network location</a></h3>
-
- <p>GrapheneOS provides network-based location as an opt-in feature with our own
- implementation. Similar to the services provided by Apple and Google, it offers
- location detection based on nearby networks rather than solely relying on using
- satellite-based location (GNSS) with technologies to accelerate it (A-GNSS). It
- makes getting a location indoors and in cities with tall buildings much faster
- or possible when it wouldn't have worked via GNSS. Certain apps also have the
- expectation of network-based location being available and don't account for the
- time needed to get a GNSS-based estimate or inability to get one everywhere so
- this feature provides improved compatibility with apps.</p>
-
- <p>Unlike Google's service and similar to Apple's service, our feature provides
- local position estimation based on retrieving location data for nearby networks
- from a service. It caches the information from the service in-memory for up to
- 15 minutes from when it was last used so it can function offline after getting
- the initial data. It only needs to send a network identifier for each network it
- wants to use for position estimation. Google's service does server-side position
- estimation which requires repeatedly sending distance estimates for each network
- to the service for each position estimate update. The approach we use doesn't
- require providing any information to the service once the nearby networks are in
- the cache or sending distance estimates. The service also provides it with extra
- data covering a fairly large area from the initial position with a reasonable
- density of networks so it can keep functioning if internet access is lost.</p>
-
- <p>Our network-based location feature is currently entirely based on Wi-Fi
- Access Points (APs). It will be extended with support for cell towers in the
- near future to provide better support for rural locations like the Apple and
- Google services. Apple and Google also use Bluetooth beacons but it's a very
- niche feature only relevant to certain malls, stores, etc. which are usually
- covered well enough by Wi-Fi support for decent position estimates.</p>
-
- <p>Users can currently choose between using our proxy to Apple's service or
- directly using Apple's service. We're in the process of building our own
- database and service based on data from multiple sources including Apple's
- service. Unlike the Apple and Google services, our service will provide support
- for fully offline usage based on database downloads rather than requiring
- sending network identifiers to the service to fetch data for them.</p>
-
- <p>For details on how to use the network location feature, see the
- <a href="/usage#network-location">usage section</a>.</p>
- </section>
-
- <section id="private-screenshots">
- <h3><a href="#private-screenshots">Private screenshots</a></h3>
-
- <p>GrapheneOS disables the inclusion of sensitive metadata in screenshots.</p>
-
- <p>On Android, each screenshot includes an EXIF Software tag with detailed OS
- build/version information (<code>android.os.Build.DISPLAY</code>). It's the
- same value shown at <b>Settings&#160;<span aria-label="and then">></span>
- About device&#160;<span aria-label="and then">></span> Build number</b>. This
- leaks the OS, OS version and also usually the device family/model since builds are
- specific to a family of devices. GrapheneOS completely disables this
- tag.</p>
-
- <p>On Android, each screenshot also includes EXIF tags with the local date,
- time and timezone offset. GrapheneOS disables this by default to
- avoid leaking the time and quasi-location information through metadata that
- isn't visible to the user. The date and time are already included in the file
- name of the screenshot which is fully visible to the user and can be easily
- modified by them without a third-party tool. GrapheneOS includes a toggle for
- turning this metadata back on in <b>Settings&#160;<span aria-label="and then">></span>
- Security &amp; privacy&#160;<span aria-label="and then">></span>
- More security &amp; privacy</b> since some users may find it to be useful.</p>
- </section>
-
- <section id="closed-device-identifier-leaks">
- <h3><a href="#closed-device-identifier-leaks">Closed device identifier leaks</a></h3>
-
- <p>GrapheneOS fixes several prominent device identifier leaks bypassing
- Android's intention of apps not being able to uniquely identify a device. See
- our FAQ sections on <a href="/faq#hardware-identifiers">hardware
- identifiers</a> and <a href="/faq#non-hardware-identifiers">non-hardware
- identifiers</a> for more general information.</p>
-
- <p>Our <a href="/usage#exec-spawning">secure application spawning system</a>
- primarily exists to significantly improve protection against exploitation.
- However, it also improves privacy. On a device without our secure application
- spawning system, the secrets used for probabilistic exploit mitigations such
- as ASLR are usable as device identifiers persisting until reboot. This is an
- easy way to identify the device from apps in different profiles. It's a minor
- bonus of the feature and there are still plenty of side channels to identify
- devices across apps, but it fixes most of the known direct identifier
- leaks.</p>
-
- <p>We also eliminate several holes in preventing apps from accessing hardware
- identifiers including tightening up the restrictions for apps targeting legacy
- Android platform versions.</p>
- </section>
-
- <section id="privacy-by-default">
- <h3><a href="#privacy-by-default">Privacy by default</a></h3>
-
- <p>GrapheneOS doesn't include or use Google apps and services by default and
- avoids including any other apps/services not aligned with our privacy and
- security focus. Google apps and services can be used on GrapheneOS as regular
- sandboxed apps without any special access or privileges through our <a
- href="#sandboxed-google-play">sandboxed Google Play</a> feature, but we don't
- include those apps by default to give users an explicit choice on whether they
- want to use those apps and which profiles they want to use it in.</p>
-
- <p>We change the default settings to prefer privacy over small conveniences:
- personalized keyboard suggestions based on gathering input history are
- disabled by default, sensitive notifications are hidden on the lockscreen by
- default and passwords are hidden during entry by default.</p>
-
- <p>Some of our changes for <a href="#attack-surface-reduction">attack surface
- reduction</a> can also improve privacy by default by not exposing unnecessary
- radios, etc. by default and avoiding the impact of potential privacy bugs with
- the hardware.</p>
-
- <p>By default, we also use GrapheneOS servers for the following services
- instead of Google servers:</p>
-
- <ul>
- <li>Connectivity checks</li>
- <li>Attestation key provisioning</li>
- <li>GNSS almanac downloads (PSDS) for Broadcom and Qualcomm (XTRA)</li>
- <li>Secure User Plane Location (SUPL)</li>
- <li>Network time</li>
- <li>Vanadium (Chromium) component updates</li>
- </ul>
-
- <p>We provide a toggle to switch back to Google's servers for connectivity
- checks, attestation key provisioning and GNSS almanac downloads along with
- adding proper support for disabling network time connections. This combines
- with other toggles to allow making a GrapheneOS device appear to be an AOSP
- device. This is only particularly important for connectivity checks since the
- other connections get routed through a VPN which is needed to blend in on a
- local network in practice.</p>
-
- <p>In addition to our SUPL privacy improvements, we override the SUPL server
- to our proxy by default. We also add a toggle for users to switch to the
- standard SUPL server for their carrier (usually supl.google.com) or disable it
- entirely.</p>
-
- <p>See our <a href="/faq#default-connections">default connections FAQ entry
- for much more detailed information</a>.</p>
- </section>
-
- <section id="pin-scrambling">
- <h3><a href="#pin-scrambling">PIN scrambling</a></h3>
-
- <p>GrapheneOS adds a toggle for enabling PIN scrambling to raise the
- difficulty of figuring out the PIN being entered by a user either due to
- physical proximity or a side channel. PIN scrambling is applied to both the
- lock screen and SIM PIN/PUK.</p>
- </section>
-
- <section id="two-factor-fingerprint-unlock">
- <h3><a href="#two-factor-fingerprint-unlock">Two-factor fingerprint unlock</a></h3>
-
- <p>GrapheneOS adds the option to require entering a 2nd factor PIN after
- successfully authenticating with a fingerprint on the lockscreen in order to
- complete unlocking the device. Since Android/iOS use biometric unlock as a
- secondary unlock mechanism for convenience, this allows users to make use of a
- strong passphrase as their primary unlock method with the convenience of a
- fingerprint and short PIN for secondary unlock. Failure to enter the correct PIN
- counts towards the standard attempt limit.</p>
- </section>
-
- <section id="supports-longer-passwords">
- <h3><a href="#supports-longer-passwords">Supports longer passwords</a></h3>
-
- <p>GrapheneOS supports setting longer passwords by default: 128 characters
- instead of 16 characters. This avoids the need to use a device manager to
- enable this functionality.</p>
-
- <p>This feature allows users to make use of diceware passwords if they don't
- want to depend on the security of the secure element which provides very
- aggressive throttling and offers a high level of security even for a random 6
- digit PIN.</p>
- </section>
-
- <section id="auto-reboot">
- <h3><a href="#auto-reboot">Auto reboot</a></h3>
-
- <p>GrapheneOS provides an auto-reboot feature which reboots locked devices after
- a set period of time to put data at rest. A countdown timer is started each time
- the device is locked, and the device will reboot if a successful unlock doesn't
- occur before the timer reaches zero. Unlocking any profile cancels the timer,
- not just the Owner profile.</p>
-
- <p>The timer is set to 18 hours by default, but can be set to values between 10
- minutes and 72 hours, or turned off.</p>
-
- <p>This feature doesn't apply when the device is in "Before First Unlock" state,
- meaning that it will not lead to the device continuously rebooting, as data is
- already at rest.</p>
-
- <p>The feature is implemented in the init process, preventing it from being
- bypassed through system process crashes since an init crash causes a kernel
- panic which leads to a reboot.</p>
- </section>
-
- <section id="clearing-sensitive-data-from-memory">
- <h3><a href="#clearing-sensitive-data-from-memory">Clearing sensitive data from memory</a></h3>
-
- <p>As documented in our section on <a href="#exploit-mitigations">our added
- exploit mitigations</a>, GrapheneOS adds zeroing of freed memory to both the
- standard userspace and kernel allocators. These features have the secondary
- benefit of clearing sensitive data from memory as soon as possible in addition
- to defending against exploits. Android implements regular compaction of frozen
- cached apps and apps currently running in the background based on triggering a
- full compacting garbage collection (GC) and then requesting that malloc frees as
- much memory as it can back to the OS. This pairs well with zeroing features and
- results in freed data getting cleared faster for Java/Kotlin and also the C, C++
- and Rust libraries used by them where low-level allocators get held onto until
- the high level objects are freed.</p>
-
- <p>When the device is locked, we trigger full compacting garbage collection (GC)
- for the SystemUI and system_server processes to release all of the memory that's
- no longer used back to the OS. Due to GrapheneOS enabling kernel page allocator
- zeroing, this results in all the no longer referenced data in objects being
- cleared. We based our approach on Android's standard approach to running a full
- compacting GC for these two processes after the device is unlocked to clear
- remnants of the user's PIN/password and keys derived from it. This is a nice way
- to clear some data immediately after locking prior to our
- <a href="#auto-reboot">auto-reboot</a> feature kicking in to clear all of the OS
- memory.</p>
-
- <p>GrapheneOS modifies some of the ways the device can be rebooted to proceed
- with the normal reboot process where memory gets freed and cleared by the kernel
- page and slab allocator zeroing features enabled by GrapheneOS.</p>
- </section>
-
- <section id="duress">
- <h3><a href="#duress">Duress PIN/Password</a></h3>
-
- <p>GrapheneOS provides users with the ability to set a duress PIN/Password that
- will irreversibly wipe the device (along with any installed eSIMs) once entered
- anywhere where the device credentials are requested (on the lockscreen, along
- with any such prompt in the OS).</p>
-
- <p>The wipe does not require a reboot and cannot be interrupted. It can be set
- up at <b>Settings&#160;<span aria-label="and then">></span> Security &amp; privacy&#160;<span
- aria-label="and then">></span> Device unlock&#160;<span
- aria-label="and then">></span> Duress Password</b> in the owner profile. Both a
- duress PIN and password will need to be set to account for different profiles
- that may have different unlock methods.</p>
-
- <p>Note that if the duress PIN/Password is the same as the actual unlock method,
- the actual unlock method always takes precedence, and therefore no wipe will
- occur.</p>
- </section>
-
- <section id="more-secure-fingerprint-unlock">
- <h3><a href="#more-secure-fingerprint-unlock">More secure fingerprint unlock</a></h3>
-
- <p>GrapheneOS improves the security of the fingerprint unlock feature by only
- permitting 5 total attempts rather than implementing a 30 second delay between
- every 5 failed attempts with a total of 20 attempts. This doesn't just reduce
- the number of potential attempts but also makes it easy to disable fingerprint
- unlock by intentionally failing to unlock 5 times with a different finger.</p>
-
- <p>GrapheneOS also adds support for using the fingerprint scanner only for
- authentication in apps and unlocking hardware keystore keys by toggling off
- support for unlocking. This feature already existed for the standard Android
- face unlock feature.</p>
- </section>
-
- <section id="improved-user-profiles">
- <h3><a href="#improved-user-profiles">Improved user profiles</a></h3>
-
- <p>Android's user profiles are isolated workspaces with their own instances of
- apps, app data and profile data (contacts, media store, home directory, etc.).
- Apps can't see the apps in other user profiles and can only communicate with
- apps within the same user profile (with mutual consent with the other app).
- Each user profile has their own encryption keys based on their lock method.
- They're a great fit for GrapheneOS with a lot of room for improvement.</p>
-
- <p>GrapheneOS provides improvements to user profile functionality and is
- working on further improvements to make switching between them and monitoring
- other profiles much more convenient.</p>
-
- <section id="more-user-profiles">
- <h4><a href="#more-user-profiles">More user profiles</a></h4>
-
- <p>GrapheneOS raises the limit on the number of secondary user profiles to 32
- (31 + guest) instead of only 4 (3 + guest) to make this feature much more
- flexible.</p>
- </section>
-
- <section id="end-session">
- <h4><a href="#end-session">End session</a></h4>
-
- <p>GrapheneOS also enables support for logging out of user profiles without
- needing a device manager controlling the device to use this feature. Logging
- out makes profiles inactive so none of the apps installed in them can run. It
- also purges the disk encryption keys from memory and hardware registers,
- putting the user profile back at rest.</p>
- </section>
-
- <section id="disabling-app-installation">
- <h4><a href="#disabling-app-installation">Disabling app installation</a></h4>
-
- <p>GrapheneOS adds a toggle to the user management settings for disabling
- secondary user app installation. You can install the apps you want to be
- usable in a secondary user and then disable the ability to install more apps
- as that user in the Owner profile. Android supports this as a standard device
- management feature but doesn't make it available to a user who owns their own
- device.</p>
- </section>
-
-
- <section id="install-available-apps">
- <h4><a href="#install-available-apps">Improved install available apps</a></h4>
-
- <p>GrapheneOS enables the standard install available apps feature that's
- still not enabled in AOSP or the stock Pixel OS to allow the Owner user to
- install packages that are available in other users. This allows installing
- an app in a secondary user that's already installed in the Owner user
- without needing to download it again. This helps a lot with using the
- toggles added for disabling app installation by secondary users.</p>
- </section>
-
- <section id="notification-forwarding">
- <h4><a href="#notification-forwarding">Notification forwarding</a></h4>
-
- <p>GrapheneOS supports forwarding notifications from users running in the
- background to the currently active user. Forwarding notifications to other
- users is disabled by default and can be enabled within each user profile
- where forwarding to the active profile is wanted. Notifications forwarded
- from other profiles are displayed by default in a standard local
- notification channel.</p>
- </section>
- </section>
-
- <section id="grapheneos-app-repository">
- <h3><a href="#grapheneos-app-repository">GrapheneOS app repository</a></h3>
-
- <p>GrapheneOS includes our own security, minimalism and usability-focused app
- repository client for using our first-party app repository. Our app repository
- is currently used to distribute our own apps and a mirror of Google Play for
- the sandboxed Google Play feature. In the future, it will be used to
- distribute first-party GrapheneOS builds of externally developed open source
- apps with hardening applied.</p>
- </section>
-
- <section id="vanadium">
- <h3><a href="#vanadium">Vanadium: hardened WebView and default browser</a></h3>
-
- <p>GrapheneOS includes our Vanadium browser as WebView implementation provided
- by the OS and our default browser. Vanadium is a hardened variant of Chromium
- providing enhanced privacy and security, similar to how GrapheneOS compares to
- AOSP. The Vanadium browser currently doesn't add many features but there are a
- lot of enhancements planned in the long term.</p>
-
- <p>Some of the features added compared to standard mobile Chromium:</p>
-
- <ul>
- <li>Hardware memory tagging (MTE) enabled for the main allocator</li>
- <li>Type-based Control Flow Integrity (CFI)</li>
- <li>Strong stack protector</li>
- <li>Automatic zero-initialized variables</li>
- <li>Well-defined signed overflow</li>
- <li>Strict site isolation and sandboxed iframes</li>
- <li>JavaScript JIT disabled by default with per-site toggle via drop-down
- permission menu</li>
- <li>Dynamic code execution is blocked for processes without the JavaScript
- JIT enabled as an extension to the seccomp-bpf sandbox</li>
- <li>Native Android autofill implementation to avoid needing sandboxed Google
- Play for autofill support</li>
- <li>Native Android credential manager support for passkeys to avoid needing
- sandboxed Google Play for passkey support</li>
- <li>WebGPU disabled for attack surface reduction</li>
- <li>WebRTC IP handling policy toggle to control peer-to-peer WebRTC mode</li>
- <li>High performance content filtering engine using EasyList + EasyPrivacy
- with per-site toggle via drop-down permission menu</li>
- <li>More complete state partitioning without origin trial opt-out</li>
- <li>Standard Android 16 user agent reduction is enabled early for the
- WebView to replace the major OS version, device model and browser
- minor/build/patch version with standard placeholder values</li>
- <li>High entropy client hints are replaced with the standard placeholder
- values used in Chromium's reduced user agent for both the browser and
- WebView to close a loophole where Chromium is still sharing the major OS
- version, device model and browser minor/build/patch version with any server
- requesting it via client hints</li>
- <li>Battery API always shows the battery as charging and at 100% capacity</li>
- <li>Trivial subdomain hiding disabled</li>
- <li>Consistent browser behavior across users without usage of feature flags
- and seed-based trials</li>
- <li>Nearly all remote services disabled by default or removed. Only connects
- to GrapheneOS servers by default. There are only 2 default services:
- component updates such as certificate authority and certificate revocation
- updates and DNS-over-HTTPS connectivity checks when enabled</li>
- <li>Web search and global search intents to replace the need for an OS
- search app</li>
- <li>Option to always open links from other apps, custom tabs, search intents
- and share intents in Incognito mode</li>
- <li>Option to reduce or disable sending cross-origin referrer information
- sharing where a link was opened</li>
- <li>Hybrid post-quantum cryptography enabled by default to match the
- behavior of Chromium on desktop since the devices we support are more
- than fast enough</li>
- </ul>
-
- <p>Better default settings, including non-user-facing flags:</p>
-
- <ul>
- <li>Reduce Accept-Language header by default (only available via
- chrome://flags)</li>
- <li>Third party cookies disabled by default</li>
- <li>Payment support disabled by default</li>
- <li>Website background sync disabled by default</li>
- <li>Sensors access disabled by default</li>
- <li>Protected media (DRM) disabled by default</li>
- <li>Hyperlink auditing disabled by default</li>
- <li>Do Not Track enabled by default mainly to avoid users differentiating
- themselves from others by enabling it since it has no real value</li>
- <li>WebRTC IP handling policy set to the most private value by default
- instead of the least private value (turned into a user-facing option by
- Vanadium)</li>
- </ul>
-
- <p>Configurable features such as JS JIT disabling and content filtering are
- currently exclusive to the Vanadium browser. Vanadium WebView is currently
- excluded from these changes until it has an app setting configuration menu
- similar to the standard site setting configuration menu.</p>
-
- <p>Extension support isn't planned due to being at odds with site isolation and
- anti-fingerprinting. We plan to implement more features as part of the browser
- with a focus on privacy and security improvements which can be active by default
- rather than opt-in niche features. Improvements will generally be opt-out on a
- per-site basis rather than opt-in to provide privacy and security by default and
- to avoid users making themselves more identifiable by opting into privacy and
- security features. Default-disabled JS JIT and default-enabled content filtering
- are early examples of this approach we plan to expand upon.</p>
-
- <p>We plan to add more site settings toggles related to attack surface reduction
- such as site setting toggles for WebGL, WebGPU, WebRTC and other features which
- are normally always enabled. This will help with both security and improving the
- defenses against fingerprinting.</p>
-
- <p>Anti-fingerprinting depends on having a large userbase with the same browser,
- extensions, content filters and other web-facing configuration. Once Vanadium
- has more features, it will be made available outside GrapheneOS to expand the
- userbase. Our approach to attack surface reduction eliminates fingerprinting
- methods in addition to attack surface for exploits and this will be a key part
- of how we approach preventing fingerprinting by not having features like WebGL,
- WebGPU and WebRTC exposed in the first place. Good defaults and avoiding having
- users changing web-facing configuration is an important part of this. Content
- filters will remain standard across users and updated together as part of the
- Vanadium configuration app. We'll address the need for language-focused filters
- by enabling them based on browser language configuration. Fingerprinting based
- on hardware differences will become more relevant once Vanadium is available
- outside of GrapheneOS which will always support a small set of highly secure
- devices.</p>
-
- <p>State partitioning still needs to be fully completed. The main remaining
- hurdle is providing full cookie partitioning. Mainstream browsers with this
- feature rely on heuristics bypassing cookie partitioning which can be easily
- abused to bypass the feature. We tried deploying full cookie partitioning by
- default but had to roll it back and will need to consider how to approach this
- particularly with our goal of having most Vanadium users using nearly the same
- configuration.</p>
-
- <p>We plan to move to a better content engine with support for more advanced
- filter rules and cosmetic filtering in the future. Expanding the standard
- filters will depend on having support for the extensions used by uBlock Origin,
- AdGuard and other filters.</p>
-
- <p>Most browser data is currently excluded from OS backups, which will likely be
- changed once GrapheneOS has a better backup service included. Export/import for
- bookmarks and similar data export/import features are also planned. Sync beyond
- OS backup service support which will eventually provide per-app backup and
- restore including across devices and via sync services is not planned.</p>
-
- <p>More information is available in the <a href="/usage#web-browsing">web
- browsing section of our usage guide</a>.</p>
- </section>
-
- <section id="auditor">
- <h3><a href="#auditor">Auditor app and attestation service</a></h3>
-
- <p>Our <a href="https://github.com/GrapheneOS/Auditor/releases">Auditor
- app</a> and <a href="https://attestation.app/">attestation service</a>
- provide strong hardware-based verification of the authenticity and integrity
- of the firmware/software on the device. A strong pairing-based approach is
- used which also verifies the device's identity based on the
- hardware-backed key generated for each pairing. Software-based checks are
- layered on top with trust securely chained from the hardware. For more
- details, see the <a href="https://attestation.app/about">About</a> and
- <a href="https://attestation.app/tutorial">Tutorial</a> pages.</p>
- </section>
-
- <section id="grapheneos-camera">
- <h3><a href="#grapheneos-camera">GrapheneOS Camera</a></h3>
-
- <p><a href="/usage#grapheneos-camera-app">GrapheneOS Camera</a> is a modern
- camera app with a great user interface and a focus on privacy and
- security. More details are available in the <a href="/usage#camera">camera
- section of our usage guide</a>.</p>
- </section>
-
- <section id="grapheneos-pdf-viewer">
- <h3><a href="#grapheneos-pdf-viewer">GrapheneOS PDF Viewer</a></h3>
-
- <p><a href="https://github.com/GrapheneOS/PdfViewer">GrapheneOS PDF Viewer</a>
- is a sandboxed, hardened PDF viewer using HiDPI rendering with features like
- pinch to zoom, text selection, viewing encrypted PDFs, etc.</p>
- </section>
-
- <section id="setup-wizard">
- <h3><a href="#setup-wizard">Setup Wizard</a></h3>
-
- <p>We have our own Setup Wizard for the initial setup of the device and for user
- profiles. It's very similar to the Setup Wizard in the stock Pixel OS but has
- more emphasis on security. It detects an unlocked bootloader at the start and
- warns the user about it with a button for rebooting to fastboot mode in order to
- lock the device. Skipping the warning requires waiting for a timer to prevent
- quickly skipping through it and missing the important information. Our setup
- wizard also disables OEM unlocking by default at the end of the process with a
- toggle to opt-out of it being disabled, which is a small but useful reduction in
- attack surface. We plan to include our improvements to lock method options in
- our Setup Wizard including 2-factor fingerprint authentication along with
- generating random diceware passphrases and PINs automatically.</p>
- </section>
-
- <section id="encrypted-backups">
- <h3><a href="#encrypted-backups">Encrypted backups</a></h3>
-
- <p>Encrypted backups via integration of the
- <a href="https://github.com/GrapheneOS/platform_external_seedvault">Seedvault
- app</a> with support for local backups and any cloud storage provider with a
- storage provider app.</p>
-
- <p>Seedvault was created by a GrapheneOS community member for inclusion in our
- operating system. We plan on replacing it with a new implementation since the
- project has been taken over by another group of people not sharing our goals
- or approach. For now, this is the best available option, so we're including it
- to give people encrypted backup support. We've made several security fixes to
- work around upstream issues with the project.</p>
- </section>
-
- <section id="location-data-access-indicator">
- <h3><a href="#location-data-access-indicator">Location data access indicator</a></h3>
-
- <p>GrapheneOS enables the privacy indicator for location data access in
- addition to the standard Android camera and microphone indicators. This shows
- an indicator when an app the user has granted permission to access location
- requests location data. We also resolve various UX issues with this feature as
- it currently exists in AOSP to get it into a highly usable state.</p>
-
- <p>Android 13 has the location privacy indicator as a developer option but it
- doesn't work the same way as it does in GrapheneOS. GrapheneOS shows it for
- all location data accesses through any APIs. Normally, the stock OS only shows
- it for GNSS location requests, also known as high power location requests, and
- doesn't normally show it for network location and other APIs gated by the
- Location permission / global block toggle.</p>
-
- <p>The indicator works the same way as the Camera and Microphone ones, showing
- a bright green icon when location access occurs which then gets minimized to a
- small bright green dot when the quick settings tray isn't currently opened.
- Android 12 already includes Location with the other standard runtime
- permissions in the privacy dashboard for viewing the history.</p>
- </section>
-
- <section id="user-installed-apps-can-be-disabled">
- <h3><a href="#user-installed-apps-can-be-disabled">User installed apps can be disabled</a></h3>
-
- <p>GrapheneOS adds support for disabling user installed apps instead of only
- being able to disable system apps. This allows users to completely prevent one
- of the apps they've installed from being able to run without being forced to
- uninstall it and lose their app data. This is much stricter than the standard
- force stop feature which only prevents an app from starting itself and the app
- will start running again as soon as another app tries to open an activity or
- service it provides.</p>
- </section>
-
- <section id="improved-vpn-leak-blocking">
- <h3><a href="#improved-vpn-leak-blocking">Improved VPN leak blocking</a></h3>
-
- <p>GrapheneOS greatly improves Android's protection against VPN leaks for both
- the built-in VPN support and VPN apps with the standard "Block connections
- without VPN" toggle enabled.</p>
-
- <p>Android allows DNS queries from the system resolver to leak to the network
- provided DNS servers when a VPN app goes down due to a race condition. It also
- similarly allows connections to the VPN DNS servers to happen outside of the VPN
- tunnel. Both of these are fully prevented by GrapheneOS through extending the
- leak blocking to this part of the system resolver, fully preventing unicast DNS
- leaks.</p>
-
- <p>Android allows processes including apps to bypass the VPN entirely whether
- it's up or down by sending multicast packets either directly or by causing the
- kernel to send the packets on their behalf through the standard multicast group
- management system calls. GrapheneOS extends Android's standard eBPF filtering
- with full support for blocking all forms of multicast packet bypasses.</p>
-
- <p>Android VPN configuration is split up for each profile which means work
- profiles, Private Spaces and secondary users have their own VPN configuration
- which is a fantastic privacy feature. Android has a standard restriction
- preventing processes from using a network which the current profile isn't
- allowed to access. However, this doesn't take multicast packets into account and
- it's possible to send multicast packets via VPN tunnels belonging to a different
- profile. GrapheneOS addresses this by extending the standard netfilter
- configuration with a multicast firewall preventing sending packets through a VPN
- tunnel which a process isn't supposed to be able to access.</p>
-
- <p>Finding and resolving all forms of VPN leaks is one of our top priorities at
- the moment and we don't currently consider this to be a complete feature due to
- less severe additional issues we've discovered.</p>
- </section>
-
- <section id="log-viewer-and-crash-reporting">
- <h3><a href="#log-viewer-and-crash-reporting">Log viewer and user-facing crash reporting</a></h3>
-
- <p>GrapheneOS adds a user-facing log viewer to the Settings app for Android's
- standard in-memory logging system. The feature acts as a substitute for
- automated crash reporting which is not implemented by GrapheneOS for privacy
- reasons. Instead, users are in control of what's captured and shared. Our log
- viewer supports filtering the output based on log level, log buffers and text
- search. Users can copy, share or save the currently shown logs to a file. A
- description can be added to document why the logs were captured.</p>
-
- <p>Overall system logs can be accessed at <b>Settings&#160;<span aria-label="and then">></span>
- System&#160;<span aria-label="and then">></span> View logs</b>. Per-app logs can
- be accessed at <b>Settings&#160;<span aria-label="and then">></span>
- Apps&#160;<span aria-label="and then">></span> App name&#160;<span
- aria-label="and then">></span> View logs</b>.</p>
-
- <p>We implement user-facing crash reporting tied to our log viewer for OS and
- app crashes, greatly improving upon the very limited user-facing crash reporting
- available in Android. This helps users report crashes to the OS or app
- developers without requiring invasive automated crash reporting where users
- don't control the data that's sent to developers.</p>
-
- <p>Our user-facing crash reporting has special support for memory corruption
- caught by hardened_malloc and hardware memory tagging informing users that
- memory corruption was detected. Users choose how to proceed and whether it makes
- sense to enable our compatibility toggles for the app if they don't believe it
- was an exploit but rather an app bug they need to work around. It's a careful
- balance between not encouraging users to disable security features protecting
- user installed apps from exploits and making it easy to work around app bugs. We
- don't allow disabling these exploit protection features for the base OS
- including base OS apps, but too many user installed apps have latent memory
- corruption bugs and we need to provide the option to work around them.</p>
-
- <p>Users can enable more system crash reporting via <b>Settings&#160;<span aria-label="and then">></span>
- Security &amp; privacy&#160;<span aria-label="and then">></span>
- More security &amp; privacy&#160;<span aria-label="and then">></span>
- Notify about system process crashes</b>. We don't enable reporting all kernel or
- system process crashes by default since we can't manage triaging and
- investigating every single Android OS bug causing a crash. We're focused on the
- memory corruption crashes caught by hardware memory tagging so those are always
- reported. Fixing every Android bug ourselves is not something we can hope to
- accomplish so we focus our resources on the ones found by our improvements which
- also have a higher chance of being security bugs.</p>
- </section>
-
- <section id="other-features">
- <h3><a href="#other-features">Other features</a></h3>
-
- <p>This is an incomplete list of other GrapheneOS features.</p>
-
- <ul>
- <li>Per-profile encrypted file name padding increased from 16 bytes to 32
- bytes to reduce the information leaked through file name lengths. See the
- FAQ section on <a href="/faq#encryption">the filesystem-based full disk
- encryption</a> used by modern Android and GrapheneOS for more information.</li>
- <li>Improved user visibility into persistent firmware security through version
- and configuration verification with reporting of inconsistencies and debug
- features being enabled.</li>
- <li>Authenticated encryption for network time updates via a first-party server to
- prevent attackers from changing the time and enabling attacks based on bypassing
- certificate / key expiry, etc.</li>
- <li>Proper support for disabling network time updates rather than just not using
- the results</li>
- <li>Hardened local build / signing infrastructure</li>
- <li><a href="/usage#updates">Seamless automatic OS update system</a> that just
- works and stays out of the way in the background without disrupting device
- usage, with full support for the standard automatic rollback if the first boot
- of the updated OS fails</li>
- <li>Require unlocking to access sensitive functionality via quick tiles</li>
- <li><a href="/faq#bundled-apps">Minimal bundled apps and services</a>. Only
- essential apps are integrated into the OS. We don't make partnerships with
- apps and services to bundle them into the OS. An app may be the best choice
- today but a poor choice in the future, and vice-versa. Our approach will be recommending certain
- apps during the initial setup, not hard-wiring them into the OS.</li>
- <li>Wireless alerts are completely optional since GrapheneOS adds a toggle for
- the otherwise mandatory presidential alert type. This is particularly
- useful in Canada where the government abuses the system and sends every
- type of alert as a presidential alert to stop users from being able to opt
- out of weather and amber alerts.</li>
- <li>Removal of TrustCor root certificate authority as a trusted system CA.</li>
- <li>Secure-by-default Android 12 PendingIntent security check (FLAG_IMMUTABLE)
- instead of crash-by-default improving older app compatibility and security.</li>
- <li>Fixed UART debugging enabled warning on official release builds.</li>
- <li>Engineering / Prototype ("EVT", "PVT" or "DVT") device warning as these
- devices typically have relaxed security controls for development, mainly
- the secure boot state property <code>ro.boot.secure_boot</code> not set
- to <code>PRODUCTION</code>.</li>
- <li>Enable bootloader, radio, and boot partition version / fingerprint
- checks.</li>
- <li>Remove code automatically granting the location permission to system
- browsers.</li>
- <li>Apps that don't have any storage permission aren't allowed to read the
- list of all user-created directories (this is allowed on Android). The list of
- files is hidden from such apps on both Android and GrapheneOS.</li>
- <li>Screenshot shutter sound is toggleable using the <b>Tap &amp; click
- sounds</b> option in <b>Settings&#160;<span aria-label="and then">></span>
- Sound &amp; vibration</b> while still following the standard method of
- putting the device on vibration/silent mode to turn off the screenshot shutter
- sound.</li>
- <li>More precise system clock via lowering the system clock time update
- threshold from 2000ms to 50ms and lowering the system clock drift warning
- from 2000ms to 250ms. This can be helpful for time-based protocols such as
- TOTP.</li>
- <li>Call recording functionality within the Dialer app using modern Android
- storage with recordings stored in Recordings/Call Recordings and no restrictions based
- on region or special cases like playing a recording tone (users are still responsible
- for complying with their local laws).</li>
- <li>Change standard Android package installer behavior to preserving
- packages being disabled after updating them instead of them being
- re-enabled.</li>
- <li>Enable the "Always-on VPN" and "Block connections without VPN" toggles
- for VPNs by default.</li>
- <li>Permission prompts and the Android Debug Bridge USB authorization prompt
- have the allow action disabled by default with a 1 second delay before it
- becomes active. This protects against accidental presses, especially since
- an app can trick the user into doing it by having them push a button where
- the system dialog will be displayed.</li>
- </ul>
- </section>
- </section>
-
- <section id="services">
- <h2><a href="#services">Services</a></h2>
-
- <p>Service infrastructure features:</p>
-
- <ul>
- <li>Strict privacy and security practices for our infrastructure</li>
- <li>Unnecessary logging is avoided, and logs are automatically purged after 4
- days (network services used by the OS) to 10 days</li>
- <li>Services are hosted entirely via our own dedicated servers and virtual
- machines from OVH (and BuyVM for mirrors) without involving any additional
- parties for CDNs, SaaS platforms, mirrors or other services</li>
- <li>Our services are built with open technology stacks to avoid being locked into
- any particular hosting provider or vendor</li>
- <li>Open documentation on our infrastructure including listing out all of our
- services, guides on making similar setups, published configurations for each
- of our web services, etc.</li>
- <li>No proprietary services</li>
- <li>Authenticated encryption for all of our services</li>
- <li>Strong cipher configurations for all of our services (SSH, TLS, etc.) with
- only modern AEAD ciphers providing forward secrecy</li>
- <li>Our web sites do not include any third party content and entirely forbid
- it via strict Content Security Policy rules</li>
- <li>Our web sites disable referrer headers to maximize privacy</li>
- <li>Our web sites fully enable cross origin isolation and disable embedding in
- other content</li>
- <li><a href="https://internet.nl/faqs/dnssec/">DNSSEC</a> implemented for all
- of our domains to provide a root of trust for encryption and authentication
- for domain/server configuration</li>
- <li>DNS Certification Authority Authorization (CAA) records for all of our
- domains permitting only Let's Encrypt to issue certificates with fully
- integrated support for the <code>accounturi</code> and
- <code>validationmethods</code> pinning our Let's Encrypt accounts as the only
- ones allowed to issue certificates</li>
- <li>DANE TLSA records for pinning keys for all our TLS services</li>
- <li>Our mail server enforces DNSSEC/DANE to provide authenticated encryption
- when sending mail including alert messages from the attestation service</li>
- <li>SSHFP across all domains for pinning SSH keys</li>
- <li>Static key pinning for our services in apps like Auditor</li>
- <li>No persistent cookies or similar client-side state for anything other than
- login sessions, which are set up securely using <code>SameSite=Strict</code>,
- <code>Secure</code>, <code>HttpOnly</code>, and <code>Path=/</code> flags, prefixed with
- <code>__Host</code> and have server-side session tracking with the ability to log out
- of other sessions</li>
- <li>scrypt-based password hashing (likely Argon2 when the available implementations
- are more mature)</li>
- </ul>
- </section>
-
- <section id="project">
- <h2><a href="#project">Project</a></h2>
-
- <p>Beyond the technical features of the OS:</p>
-
- <ul>
- <li>Collaborative, <a href="/source">open source project</a> with a
- <a href="/contact#community">very active community</a> and contributors</li>
- <li>You can make your own builds and make desired changes, so you aren't stuck with
- the decisions made by the upstream project</li>
- <li>Non-profit project avoiding conflicts of interest by keeping commercialization
- at a distance. Companies support the project
- <a href="/faq#company">rather than the project serving the needs of any
- particular company</a></li>
- <li><a href="/faq#privacy-policy">Strong privacy policies</a> across all our
- software and services</li>
- <li><a href="/history/">Proven track record</a> of the team standing up
- against attempts to compromise the integrity of the project and placing it
- above personal gain</li>
- </ul>
- </section>
- </main>
- {% include "footer.html" %}
- </body>
-</html>
diff --git a/static/package.html b/static/package.html
new file mode 100644
index 00000000..b28beb5e
--- /dev/null
+++ b/static/package.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html lang="en" prefix="og: https://ogp.me/ns#">
+ <head>
+ <meta charset="utf-8"/>
+ <title>Package | Hakurei</title>
+ <meta name="description" content="Overview of the planterette package manager and its interactions with Hakurei.."/>
+ <meta name="theme-color" content="#212121"/>
+ <meta name="color-scheme" content="dark light"/>
+ <meta name="msapplication-TileColor" content="#ffffff"/>
+ <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"/>
+ <meta property="og:title" content="Planterette packaging overview"/>
+ <meta property="og:description" content="Overview of the planterette package manager and its interactions with Hakurei."/>
+ <meta property="og:type" content="website"/>
+ <meta property="og:image" content="https://hakurei.app/opengraph.png"/>
+ <meta property="og:image:width" content="512"/>
+ <meta property="og:image:height" content="512"/>
+ <meta property="og:image:alt" content="Hakurei logo"/>
+ <meta property="og:site_name" content="Hakurei"/>
+ <meta property="og:url" content="https://hakurei.app/package.html"/>
+ <link rel="canonical" href="https://hakurei.app/package.html"/>
+ <link rel="icon" href="/favicon.ico"/>
+ <link rel="icon" sizes="any" type="image/svg+xml" href="/favicon.svg"/>
+ <link rel="mask-icon" href="[[path|/mask-icon.svg]]" color="#1a1a1a"/>
+ <link rel="apple-touch-icon" href="/apple-touch-icon.png"/>
+ [[css|/main.css]]
+ <link rel="manifest" href="/manifest.webmanifest"/>
+ <link rel="license" href="/LICENSE.txt"/>
+ <link rel="me" href="https://port.mk/@hakurei"/>
+ [[js|/js/redirect.js]]
+ </head>
+ <body>
+ {% with current_page="package" %}
+ {% include "header.html" %}
+ {% endwith %}
+ <main id="package">
+ <h1><a href="#package">Package management</a></h1>
+
+ <p>Planterette is an experimental Android-like package manager providing
+ fully self-contained apps running in Hakurei containers. The planterette
+ software is not part of Hakurei and configures Hakurei through the public JSON API.</p>
+
+ <p>Planterette is currently in a very early stage of development, and using it for
+ anything beyond experimentation or development is not recommended.</p>
+
+ <p>If you wish to work on planterette, its source code can be found under
+ <code>cmd/planterette</code> of Hakurei's source tree. This is subject to change.
+ The Nix package builder can be accessed via the <code>buildPackage</code> output
+ of the Nix flake, however this is pending replacement.</p>
+ </main>
+ {% include "footer.html" %}
+ </body>
+</html>
diff --git a/templates/header.html b/templates/header.html
index d37d234c..46f130ba 100644
--- a/templates/header.html
+++ b/templates/header.html
@@ -2,7 +2,7 @@
<nav id="site-menu">
<ul>
<li {% if current_page == "/" %}aria-current="page"{% endif %}><a href="/"><img src="[[path|/mask-icon.svg]]" alt=""/>Hakurei</a></li>
- <li {% if current_page == "features" %}aria-current="page"{% endif %}><a href="/features.html">Features</a></li>
+ <li {% if current_page == "package" %}aria-current="page"{% endif %}><a href="/package.html">Package</a></li>
<li {% if current_page == "install" %}aria-current="page"{% endif %}><a href="/install/">Install</a></li>
<li {% if current_page == "build" %}aria-current="page"{% endif %}><a href="/build.html">Build</a></li>
<li {% if current_page == "usage" %}aria-current="page"{% endif %}><a href="/usage.html">Usage</a></li>