CVE-2026-89761 Overview
CVE-2026-89761 is an out-of-bounds write vulnerability in the Linux kernel's AppArmor label security module (LSM). The flaw resides in aa_vec_unique(), which null-terminates a vector at vec[n - dups] when the VEC_FLAG_TERMINATE flag is passed. When components are all distinct, dups is zero and the terminator is written to vec[n], one entry past the allocated buffer. The caller path aa_label_strn_parse() allocates the vector via vec_setup(), which does not reserve the terminator slot, producing an out-of-bounds write on both the local stack array and the kzalloc() heap allocation.
Critical Impact
An unprivileged local user on a system with loaded AppArmor policy can trigger a kernel memory corruption by writing a crafted label to /proc/self/attr/apparmor/current or via lsm_set_self_attr(2).
Affected Products
- Linux kernel (upstream) versions containing the vulnerable aa_vec_unique() and vec_setup() code paths in the AppArmor LSM
- Distributions shipping affected mainline and stable Linux kernel branches
- Systems with AppArmor enabled and policy loaded
Discovery Timeline
- 2026-09-11 - CVE-2026-89761 published to the National Vulnerability Database (NVD)
- 2026-09-13 - Last updated in NVD database
Technical Details for CVE-2026-89761
Vulnerability Analysis
The vulnerability is an out-of-bounds write [CWE-787] in the AppArmor label parser. aa_vec_unique() is designed to deduplicate a vector of profile pointers and, when VEC_FLAG_TERMINATE is set, append a NULL terminator at index n - dups. The function's contract requires the caller to provide space for n + 1 entries so that the terminator has a valid slot when dups == 0.
aa_label_strn_parse() violates that contract. It initializes its vector using vec_setup(profile, vec, len, gfp), which allocates exactly len entries. Below the LOCAL_VEC_ENTRIES threshold, vec_setup() uses a local stack array of LOCAL_VEC_ENTRIES pointers; above it, it calls kzalloc() for len pointers. Neither path reserves the terminator slot.
When a parsed label contains all-distinct components, aa_vec_unique() writes NULL at vec[len]. This corrupts an adjacent stack frame when len == LOCAL_VEC_ENTRIES, or an adjacent heap object when len > LOCAL_VEC_ENTRIES.
Root Cause
The root cause is a mismatch between the buffer sizing contract of aa_vec_unique() and the actual allocation performed by vec_setup() and DEFINE_VEC(). Two other VEC_FLAG_TERMINATE call sites operate on vectors sized by aa_label_alloc(), which explicitly reserves an extra slot with the comment "+ 1 for null terminator entry on vec". The parse path was missing that reservation. Additionally, label_count_strn_entries() does not bound the number of //&-separated components, so an attacker controls len.
Attack Vector
An unprivileged local task can reach the vulnerable parser through several interfaces. Writing to /proc/self/attr/apparmor/current and calling lsm_set_self_attr(2) both route through do_setattr(), which parses the label name before the change_profile permission check runs. The query_label() path exposed via the securityfs .access file is mode 0666 and performs no permission check. Every component in the label must resolve to a loaded profile, so exploitation requires a system with AppArmor policy loaded. Successful exploitation can lead to kernel memory corruption, denial of service, or local privilege escalation depending on adjacent object layout.
No public proof-of-concept exploit is currently available for CVE-2026-89761.
Detection Methods for CVE-2026-89761
Indicators of Compromise
- Unexpected kernel oops, slab-out-of-bounds reports from KASAN, or stack corruption warnings referencing aa_vec_unique, aa_label_strn_parse, or vec_setup in dmesg.
- Unprivileged processes writing unusually long or highly segmented //&-delimited strings to /proc/self/attr/apparmor/current.
- Anomalous access patterns against the securityfs .access file (/sys/kernel/security/apparmor/.access) from non-administrative accounts.
Detection Strategies
- Enable KASAN on test and staging kernels to catch the out-of-bounds write at the moment aa_vec_unique() writes the terminator.
- Instrument the LSM audit subsystem to record AA_AUDIT events tied to change_profile and label parsing failures, then baseline normal application behavior.
- Correlate lsm_set_self_attr(2) syscall telemetry with process lineage to flag unprivileged binaries attempting profile changes.
Monitoring Recommendations
- Ship auditd and kernel ring buffer logs to a central analytics tier for search on AppArmor parser errors and kernel warnings.
- Alert on repeated EINVAL or ENOMEM returns from do_setattr() originating from the same PID or user session.
- Track kernel version and AppArmor policy load state across the fleet to identify hosts eligible for exploitation.
How to Mitigate CVE-2026-89761
Immediate Actions Required
- Apply the upstream Linux kernel fix that reserves the terminator slot in vec_setup() and DEFINE_VEC() and rebuild affected kernels.
- On systems where patching is delayed, evaluate temporarily unloading AppArmor policy or disabling the AppArmor LSM if operational risk allows.
- Restrict access to the securityfs .access file by remounting securityfs with tighter permissions or applying host hardening baselines.
- Inventory all hosts running affected kernel versions with AppArmor policy loaded and prioritize multi-tenant and shared systems.
Patch Information
The fix reserves the additional entry in vec_setup() and DEFINE_VEC() so the terminator write in aa_vec_unique() stays within the allocation. Upstream commits addressing CVE-2026-89761 are available in the stable tree: Linux Kernel Commit 28069434aef6, Linux Kernel Commit 36bdd0b45ec3, Linux Kernel Commit 9124e078ea22, and Linux Kernel Commit 9f1e40193eef. Consume the fix through your distribution's kernel update channel.
Workarounds
- Restrict local shell access on multi-tenant Linux hosts until patched kernels are deployed.
- Consider disabling AppArmor at boot via apparmor=0 on the kernel command line where the security tradeoff is acceptable and other LSMs remain enforced.
- Deploy stricter seccomp filters on untrusted workloads to block the lsm_set_self_attr(2) syscall and writes to /proc/self/attr/apparmor/current.
# Verify AppArmor status and kernel version, then plan patch rollout
uname -r
aa-status || cat /sys/kernel/security/apparmor/profiles | wc -l
# Optional: disable AppArmor at next boot on hosts where policy is not required
# Edit /etc/default/grub and append apparmor=0 to GRUB_CMDLINE_LINUX, then:
sudo update-grub
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

