A janitor cleaning up a room that was never used accidentally throws away the master key that's still in someone's pocket
CVE-2023-20938 is a use-after-free in the Linux kernel's binder IPC driver, specifically in binder_transaction_buffer_release() within binder.c. When a binder transaction is submitted with an unaligned offsets_size, the kernel skips the object-processing loop but then erroneously calls the cleanup function as if objects *were* processed — decrementing reference counts on binder_node structures that haven't been touched. This drops local_strong_refs to zero, freeing the node while dangling pointers remain. An attacker can reclaim that freed memory via sendmsg heap spray, build arbitrary read/write primitives through cross-cache techniques targeting eventpoll_epi structures, and ultimately overwrite their own process credentials to UID 0 while dropping SELinux to permissive. Affected versions are Android GKI kernels 5.4 and 5.10 (pre-February 2023 security patch level), with the mainline Linux kernel also carrying the binder code in distros like Debian (fixed in 5.10.158-1, 5.17.6-1, 6.1.176-1+) and Ubuntu.
Google's vendor severity of HIGH 7.8 is appropriate for Android devices, where binder is the foundational IPC mechanism and every installed app has direct access to /dev/binder. The CVSS vector AV:L/AC:L/PR:L/UI:N accurately reflects that any low-privilege local process can trigger this without user interaction. Critically, the initial February 2023 patch was *incomplete* — the Android Red Team demonstrated a full root exploit chain on devices that had applied it — requiring a second fix under CVE-2023-21255 in July 2023. For enterprise Linux server fleets, however, the binder module is almost never loaded (it exists in the kernel source tree but is not part of standard server configs), making this effectively a non-issue on that platform. The vendor score is honest for Android but slightly overstates the risk for mixed enterprise environments.
5 steps from start to impact.
Attacker obtains local code execution on target device
- Local code execution on a device running an affected kernel (GKI 5.4/5.10 pre-July 2023 patch, or unpatched mainline Linux with binder module loaded)
- On Android, Google Play Protect and app review reduce (but don't eliminate) malicious app delivery
- On Linux servers, binder kernel module is typically not loaded —
lsmod | grep binderreturns nothing on >95% of enterprise Linux hosts - MDM policies may block sideloading on managed Android devices
/dev/binder access would catch this on servers where binder is loaded.Trigger UAF via malformed binder transaction
/dev/binder (or /dev/hwbinder) and submits a BC_TRANSACTION with a deliberately unaligned offsets_size. The kernel's binder_transaction() skips the object translation loop but still calls binder_transaction_buffer_release() with failed_at == 0, causing it to iterate over and decrement refcounts for objects that were never processed. A binder_node with local_strong_refs == 1 is freed while pointers to it persist in the transaction's binder_buffer.- Access to
/dev/binderor/dev/hwbinder(available to all Android apps; requires binder module on Linux) - Kernel version in affected range without the July 2023 complete fix
- The February 2023 partial fix changed some code paths, but the Android Red Team bypassed it — only the July 2023 patch (CVE-2023-21255) fully closes the bug
- SELinux on Android restricts which binder interfaces unprivileged apps can use, but
/dev/binderitself is accessible
Reclaim freed memory via cross-cache heap spray
sendmsg() to spray controlled data into the kmalloc-128 slab cache where the freed binder_node lived. On kernel 5.10+, the SLAB_ACCOUNT flag on eventpoll_epi forces a cross-cache technique: the exploit allocates 36×32 binder_node objects, frees them simultaneously to release the backing page, then forces the page allocator to hand that page to the eventpoll_epi cache. This gives the attacker a fake binder_node overlapping with an epitem structure.- Precise heap layout control — the PoC achieves this reliably on Cuttlefish/Goldfish AVD x86_64 with kernel 5.10.107
- Access to
epoll_create/epoll_ctlsyscalls (universally available)
- Heap layout randomization (SLAB randomization,
CONFIG_SLAB_FREELIST_RANDOM) can reduce reliability but the demonstrated exploit handles this - Different device SoCs and OEM kernel configs may require tuning the spray parameters
Build leak and arbitrary read/write primitives
ptr and cookie fields of the corrupted binder_node during subsequent transaction processing, the attacker leaks two 8-byte kernel heap values. Using the unlink primitive on struct file and struct epitem structures, the exploit modifies kernel pointers to enable arbitrary 4-byte reads via the FIGETBSZ ioctl, then chains this into a full arbitrary write primitive.- Successful heap reclamation from step 3
- Knowledge of kernel structure offsets (publicly documented for GKI 5.4/5.10)
- Kernel Address Space Layout Randomization (KASLR) adds entropy but the leak primitive in step 3 defeats it
- CONFIG_CFI_CLANG (Control Flow Integrity) can make some pointer overwrites crash instead of succeeding
Overwrite credentials and disable SELinux for root shell
struct cred in kernel memory using the arbitrary read primitive, then overwrites the uid, gid, euid, egid, suid, sgid fields to 0 (root). SELinux enforcement is disabled by toggling the selinux_enforcing global to 0 (permissive mode). Seccomp filters are cleared. The attacker now has an unrestricted root shell with full kernel-level access.- Successful arbitrary read/write from step 4
- On Pixel devices with Trusty TEE and hypervisor-based protection, credential modifications may be detected and the device rebooted
- Samsung Knox real-time kernel protection (RKP) traps credential modifications
lsmod | grep binder across your Linux fleet. If no output, the host is not exposed. If binder IS loaded (rare — typically only Android emulators or specific container runtimes), either unload it (rmmod binder_linux) or patch the kernel. Add a compliance check to your configuration management (Ansible, Puppet, Chef) to flag hosts with binder loaded.- Network segmentation / firewall rules — This is a local kernel exploit, not network-based. No amount of network controls affects the attack path.
- WAF or IDS/IPS signatures — There is no network traffic to inspect; the exploit operates entirely through local binder ioctls within the kernel.
- Android Verified Boot (AVB) — AVB protects boot-time integrity but does not prevent runtime kernel exploitation. It will detect persistent modifications on *next* boot, but the attacker already has root during the current session.
- Google Play Protect scanning alone — While Play Protect may flag known exploit payloads, a custom-compiled PoC not in Google's signature database will bypass it. Play Protect is a useful layer but not sufficient as a sole control.
The supporting signals.
| In-the-Wild Status | No confirmed ITW exploitation. Not listed in CISA KEV. No threat intelligence reports link this CVE to active campaigns or APT activity. Google's own Android Red Team demonstrated the full chain internally/at OffensiveCon 2024, but this was research, not adversary use. |
|---|---|
| Proof-of-Concept | Public, weaponized PoC available. byt3quester/CVE-2023-20938-poc on GitHub (C source, created 2026-06-22) implements the full chain: UAF trigger → cross-cache heap spray → arbitrary kernel R/W → root + SELinux bypass. Targets Cuttlefish/Goldfish AVD x86_64 kernel 5.10.107. Also jaf0rk/CVE-2023-20938 on GitHub. Google Android Red Team (Zi Fan Tan, Gulshan Singh, Eugene Rodionov) presented the full exploitation at OffensiveCon 2024 with slides and video. |
| EPSS | 0.00337 (25.5th percentile) — in the bottom quartile of all CVEs for predicted exploitation probability. Low signal, consistent with no observed ITW activity. |
| KEV Status | Not listed. No CISA Known Exploited Vulnerabilities catalog entry. |
| CVSS Vector | CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H (7.8 HIGH) — Local attack vector with low complexity and low privileges. No user interaction. Complete CIA impact but scope unchanged (no sandbox escape beyond the OS itself). The vector accurately reflects the Android threat model. |
| Affected Versions | Android GKI kernels 5.4 and 5.10 before the 2023-02-05 security patch level (partial fix) and before 2023-07-05 (complete fix via CVE-2023-21255). Mainline Linux kernel binder subsystem prior to upstream commit series. Debian fixed in 5.10.158-1 (bullseye), 5.17.6-1 (unstable), 6.1.176-1 (bookworm), 6.12.107-1 (trixie), 7.2.9-1 (forky). |
| Fixed Versions | Android: security patch level 2023-07-05 or later (complete fix). AOSP kernel commits: baa23246e93f, 3d213a626d2d, 9d1efccf5ec3, b83173bf86a9, aaf236971732. Note: the February 2023 patch was incomplete — the July 2023 patch under CVE-2023-21255 is required for full remediation. |
| Incomplete Patch History | The Feb 2023 ASB back-ported a fix that changed binder object processing, but the Android Red Team found an alternate path to reach the same UAF. CVE-2023-21255 was assigned for the bypass and fully patched in July 2023. Devices on patch levels between 2023-02-05 and 2023-07-04 remain vulnerable through the alternate path. |
| Scanning/Exposure | Binder is a local kernel interface — not network-exposed, so Shodan/Censys/GreyNoise have no visibility. Exposure assessment must be done host-by-host: check lsmod | grep binder on Linux or Android security patch level via MDM. On standard enterprise Linux servers, binder is almost never loaded. |
| Reporting Researcher | Discovered via fuzzing on android13-5.10 kernel. Full exploit chain developed and presented by Google Android Red Team: Zi Fan Tan, Gulshan Singh, Eugene Rodionov. Detailed write-up on Android Offensive Security Blog. |
Sources.
- Android Offensive Security Blog — Full Exploitation Write-up
- NVD — CVE-2023-20938 Detail
- Android Security Bulletin — February 2023
- Debian Security Tracker — CVE-2023-20938
- GitHub Advisory — GHSA-2grw-x2mc-x63f
- OffensiveCon 2024 Presentation (YouTube)
- FIRST EPSS API — CVE-2023-20938
- Binder Attack Matrix — Medium (r1971d3)
Why this verdict
- Proven full-chain exploit to kernel root: The Google Android Red Team demonstrated a complete, reliable exploit from unprivileged app to UID 0 + SELinux permissive on GKI 5.4/5.10 devices. A public PoC (byt3quester) implements this chain in C. This is not theoretical — it is weaponized. This anchors the floor at HIGH.
- Local access requirement is real but surmountable on Android: AV:L means no remote trigger, but on Android the attack surface is any installed app. Sideloading, third-party app stores, or a Play Store review bypass could deliver the payload. On enterprise MDM-managed fleets that block sideloading, friction is higher. On BYOD fleets, it is lower.
- Enterprise Linux servers are largely immune: The binder kernel module exists in the source tree but is not loaded on standard server deployments. Unless you run Android emulators (Anbox, Cuttlefish) or specific LXC/LXD configurations,
/dev/binderdoes not exist. This dramatically limits the blast radius for server-centric estates. - Patch age and gap: The complete fix shipped in July 2023 — over 3 years ago. Any Android device on security patch level 2023-07-05 or later is safe. Any Debian/Ubuntu system with current LTS kernels is patched. The residual vulnerable population shrinks monthly as devices age out.
- No ITW exploitation and bottom-quartile EPSS: EPSS at 0.00337 (25.5th percentile) with no KEV listing and no threat intel linking this to active campaigns. The exploit exists in research and PoC form but has not been weaponized by threat actors in observed incidents.
- Role multiplier: On *Android devices* (the canonical deployment for binder), a successful exploit yields full kernel compromise of that device — root shell, SELinux bypass, credential theft, MDM bypass, access to corporate email/VPN tokens. However, each device must be exploited individually; there is no lateral propagation mechanism inherent to this bug. On *managed corporate Android fleets* (~10-30% of enterprise mobile estates), this is HIGH impact. On *Linux servers* (the likely majority of a 10,000-host fleet), the binder module is not loaded on >95% of hosts — impact is effectively zero. The floor remains HIGH due to the Android mobile fleet exposure, but the blended enterprise risk is lower than a pure-Android assessment would suggest.
- Minor downgrade from 7.8 to 7.0: The vendor's 7.8 is fair for a fresh Android-only assessment. We shave 0.8 points for: (1) 3+ years of patch availability, (2) no ITW exploitation, (3) incomplete initial fix means the Feb 2023 window was still exploitable — but the July 2023 fix is ancient by now, (4) on mixed enterprise fleets, the non-Android majority is unexposed.
Why not higher?
This stays below CRITICAL because the attack vector is strictly local — no remote exploitation path exists, and there is no network propagation mechanism. The binder subsystem, while kernel-mode, is not canonically a fleet-scale infrastructure component like Active Directory, a hypervisor, or a CI/CD pipeline. Each Android device must be individually targeted with a malicious app, and the blast radius is bounded to that single device. Additionally, 3+ years of patch availability and zero ITW exploitation indicate this is not under active adversary pressure.
Why not lower?
Despite the age and low EPSS, a fully weaponized public PoC achieving kernel root from an unprivileged app with low complexity and no user interaction cannot be rated MEDIUM. The binder subsystem is present on every Android device ever shipped, representing billions of devices globally. Enterprise mobile fleets with lagging OEM patch cadences (common on Samsung, LG, and carrier-locked devices) may still have a material vulnerable population. The proven reliability of the exploit chain and the complete security posture bypass (root + SELinux off) mean that any remaining unpatched device is trivially compromisable by a local attacker.
Crowdsourced verification payload.
Run this script on each target host — Android devices via adb shell (requires USB debugging or MDM remote shell), Linux servers via SSH. No root privileges required. Invoke: bash check_cve_2023_20938.sh. The script checks Android security patch level or Linux kernel version and binder module status, then prints VULNERABLE / PATCHED / UNKNOWN.
#!/usr/bin/env bash
# check_cve_2023_20938.sh — Detect exposure to CVE-2023-20938 (binder UAF)
# Run on target host: Android via adb shell, Linux via SSH
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -euo pipefail
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
# Detect platform
if [ -f /system/build.prop ] || getprop ro.build.version.sdk >/dev/null 2>&1; then
# Android device
PATCH_LEVEL=$(getprop ro.build.version.security_patch 2>/dev/null || echo "")
if [ -z "$PATCH_LEVEL" ]; then
echo -e "${YELLOW}[UNKNOWN]${NC} Cannot read Android security patch level."
exit 2
fi
# Complete fix requires 2023-07-05 or later
REQUIRED="2023-07-05"
if [[ "$PATCH_LEVEL" > "$REQUIRED" ]] || [[ "$PATCH_LEVEL" == "$REQUIRED" ]]; then
echo -e "${GREEN}[PATCHED]${NC} Android security patch level: $PATCH_LEVEL (>= $REQUIRED)"
echo "CVE-2023-20938 and CVE-2023-21255 are both addressed."
exit 0
else
echo -e "${RED}[VULNERABLE]${NC} Android security patch level: $PATCH_LEVEL (< $REQUIRED)"
echo "Device is missing the complete fix for CVE-2023-20938."
# Check if partial fix is present
PARTIAL="2023-02-05"
if [[ "$PATCH_LEVEL" > "$PARTIAL" ]] || [[ "$PATCH_LEVEL" == "$PARTIAL" ]]; then
echo "NOTE: Partial fix (Feb 2023) is applied, but bypass via CVE-2023-21255 exists."
fi
exit 1
fi
else
# Linux server/workstation
KERNEL=$(uname -r)
echo "Kernel version: $KERNEL"
# Check if binder module is loaded or built-in
BINDER_LOADED=0
if lsmod 2>/dev/null | grep -qi binder; then
BINDER_LOADED=1
echo "Binder module: LOADED (host is potentially exposed)"
elif [ -e /dev/binder ] || [ -e /dev/hwbinder ] || [ -e /dev/vndbinder ]; then
BINDER_LOADED=1
echo "Binder device node: FOUND (binder may be built-in)"
else
echo -e "${GREEN}[PATCHED]${NC} Binder module is NOT loaded and /dev/binder does not exist."
echo "This host is not exposed to CVE-2023-20938 (binder subsystem inactive)."
exit 0
fi
if [ "$BINDER_LOADED" -eq 1 ]; then
# Check known-fixed kernel versions for major distros
# Debian bullseye: fixed in 5.10.158-1
# Debian bookworm: fixed in 6.1.176-1
# Upstream: fixed in 5.17.6+
echo -e "${YELLOW}[UNKNOWN]${NC} Binder is active on kernel $KERNEL."
echo "Manual verification required:"
echo " - Debian bullseye: need >= 5.10.158-1"
echo " - Debian bookworm: need >= 6.1.176-1"
echo " - Upstream: need >= 5.17.6 or backported patch"
echo " - Check: apt list --installed 2>/dev/null | grep linux-image"
echo " - Check: rpm -q kernel 2>/dev/null"
exit 2
fi
fi