CVE-2026-19669
Executive Summary
CVE-2026-19669 is an out-of-bounds write (CWE-787) in the Zephyr RTOS user-mode syscall verifiers z_vrfy_fuel_gauge_get_props() and z_vrfy_fuel_gauge_set_props(), which declare variable-length arrays sized directly by an unvalidated, caller-supplied len argument before any bounds or permission check occurs. Any unprivileged thread running in user mode on a CONFIG_USERSPACE-enabled Zephyr build can supply an oversized len to displace the supervisor stack pointer, corrupt the privileged stack, and — if it holds a fuel-gauge device object handle — write fully attacker-controlled data out of bounds below the privileged stack base. With CVSS 7.8 (High), the impact is local privilege escalation and memory corruption in the embedded kernel's most trusted execution context.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Technical Analysis
The defect resides in drivers/fuel_gauge/fuel_gauge_syscall_handlers.c. The two verifier functions z_vrfy_fuel_gauge_get_props() and z_vrfy_fuel_gauge_set_props() declared two variable-length arrays:
union fuel_gauge_prop_val k_vals[len]fuel_gauge_prop_t k_props[len]
Both arrays are sized directly by the caller-supplied len argument. That len is an unvalidated size_t taken straight from the syscall ABI, and — critically — the VLAs were allocated before any check at all, including before the K_SYSCALL_DRIVER_FUEL_GAUGE() object-permission check. This ordering is the root cause: in Zephyr's syscall verification model, the verifier is supposed to validate arguments and permissions before committing kernel-side resources. Here the resource commitment (stack allocation sized by attacker input) precedes validation.
The subsequent k_usermode_from_copy() calls validated only that the user source buffer was readable. The kernel destination was never bounds-checked, because it was sized by the same attacker-chosen len. This creates two distinct primitives:
Stack pointer displacement. A large
lendisplaces the supervisor stack pointer by an arbitrary attacker-chosen amount. Zephyr does not build with stack-clash probing, so the displacement itself does not fault on a guard page. The nested calls the verifier then makes write frames below the privileged stack, corrupting supervisors-tack memory adjacent to the intended frame region.Attacker-controlled out-of-bounds write. If the calling thread has been granted access to a fuel-gauge device object, the
memcpyinsidek_usermode_from_copy()writeslen * sizeof(union fuel_gauge_prop_val)bytes of fully attacker-controlled data starting well below the stack base.
The exploitation budget is tight and quantitative: CONFIG_PRIVILEGED_STACK_SIZE defaults to 1024 bytes, so a len of roughly 170 already exhausts the privileged stack. Note that the OOB write volume is scaled by sizeof(union fuel_gauge_prop_val) — a union sized by its largest member — making the per-unit cost high and the achievable overflow abrupt. The trigger requires CONFIG_USERSPACE and a user-mode thread, which is the standard configuration for any Zephyr product that exposes untrusted or third-party application code (e.g., multiple partition domains on the same MCU).
The vulnerability class is a "kernel stack buffer overflow with attacker-controlled size," combined with a check-ordering flaw (TOCTOU-adjacent: allocation-by-attacker-size before authorization). The data is the kernel destination — a security-relevant distinction, because user source readability checks are irrelevant when the destination itself is sized by the attacker.
Exploitation Scenarios
No public PoC, exploit code, or Nuclei template exists; the attack chain below is inferred strictly from the vulnerability class and the details in the NVD description. No specific code patterns or hypothetical function names are invented.
Reconnaissance / target identification. An attacker obtains a foothold in user mode on a Zephyr device — for example through a compromised or malicious application partition, a remotely reachable user-mode service, or an unprivileged thread granted a fuel-gauge device object handle. The relevant precondition is
CONFIG_USERSPACEbeing enabled and a granted fuel-gauge object handle. The attacker then identifies the syscall surface for fuel-gauge property get/set operations.Triggering the flaw. The attacker invokes
fuel_gauge_get_props()orfuel_gauge_set_props()with an oversizedlen. Because the VLAs are allocated before validation, the allocation itself is the first corruption step: it displaces the supervisor stack pointer. Because Zephyr is not built with stack-clash probing, this displacement does not immediately fault. The nested calls performed by the verifier then write frames below the privileged stack.Payload/execution method (vulnerability-class level). With the displaced stack, the attacker supplies a user buffer that is readable. The
k_usermode_from_copy()memcpy then writeslen * sizeof(union fuel_gauge_prop_val)bytes of attacker-controlled data into kernel memory below the stack base. Control over content plus control over the target region — achieved by choosinglen— is the primitive. The verifier's permission check offers no defense because it executes after the allocation; in the access-granted case, it does not block the memcpy at all.Post-exploitation impact. The OOB write lands in supervisor-mode kernel memory, giving the attacker the ability to corrupt adjacent kernel data, hijack control flow, or destabilize the kernel into a denial-of-service condition. Successful exploitation yields local privilege escalation from an unprivileged user-mode thread to supervisor-mode code execution — the highest trust level on the device. On embedded/RTOS devices this can mean arbitrary code execution outside the sandbox, persistence across application-partition trust boundaries, and, on connected devices, a stepping stone to broader network or system compromise. The CVSS subscores (C:H/I:H/A:H, S:U) reflect a high-integrity and high-confidentiality breach on the affected device with no scope change.
Impact Assessment
The CVSS vector AV:L / AC:L / PR:L / UI:N / S:U / C:H / I:H / A:H yields 7.8 (High). The attack requires local access (AV:L) in the sense of running code in an unprivileged context on the device, low complexity (AC:L) because no race or probabilistic preconditions are needed — an oversized len is sufficient — and low privileges (PR:L) because only a granted user-mode thread with a fuel-gauge object handle is needed. No user interaction (UI:N) is required. Scope is unchanged (S:U) because impact is contained to the vulnerable component, but the component is the kernel itself, so "scope" understates the trust-boundary penetration.
Blast radius: every Zephyr-based product that enables CONFIG_USERSPACE and ships the fuel-gauge driver syscall handlers. This includes battery-powered embedded devices (wearables, IoT sensors, handhelds, and industrial instruments) that expose a fuel-gauge driver to user-mode code. Because CONFIG_PRIVILEGED_STACK_SIZE defaults to 1024 bytes and the overflow triggers at len ≈ 170, exploitation is both feasible and mundane — no exotic conditions.
Business impact: kernel-level memory corruption in the trusted supervisor context undermines the entire security model of a CONFIG_USERSPACE deployment, in which user-mode memory protection is supposed to contain untrusted code. A successful exploit can defeat that isolation, leading to full device compromise, safety/reliability failures (brownouts or power-management corruption that can brick or overheat a device), and — on networked devices — a pivot into adjacent systems. Note that no CISA KEV listing, EPSS score, or exploit-in-the-wild evidence is currently available, so this should be treated as a latent, high-severity exposure rather than an observed active campaign.
Detection Guidance
Detection on embedded/RTOS targets is difficult because there is no host EDR telemetry, no process tree, and typically no filesystem artifacts. The rules below are best-effort detections built from the vulnerability class and the syscall names present in the NVD description. They should be treated as monitoring primitives requiring tuning, not turnkey signatures.
Sigma Rule
title: Zephyr Fuel Gauge Syscall Verifier Oversized Length (CVE-2026-19669) — Host-Side Detection
id: 9f0a5c2e-6d41-4b8a-9f2e-2c7b6e5a1d10
status: experimental
description: Detects host-side tooling evidence (SDK/crash logs/debug probes) consistent with abuse of oversized len in z_vrfy_fuel_gauge_get_props / z_vrfy_fuel_gauge_set_props. Requires host-side collection of device logs.
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-19669
author: valtersit.com
date: 2026/01/01
tags:
- attack.t1068
- cve.2026.19669
logsource:
product: linux
service: syslog
detection:
selection_syscall:
- 'z_vrfy_fuel_gauge_get_props'
- 'z_vrfy_fuel_gauge_set_props'
- 'fuel_gauge_get_props'
- 'fuel_gauge_set_props'
selection_fault:
- '*stack*overflow*'
- '*kernel fault*'
- '*memory corruption*'
- '*oops*'
condition: selection_syscall and selection_fault
falsepositives:
- Legitimate large property reads/writes within bounds
- Boot-time sanity checks
level: high
YARA Rule
rule CVE_2026_19669_Zephyr_FuelGauge_VLA_OOB
{
meta:
description = "Detects Zephyr fuel-gauge syscall handlers with caller-sized VLA allocation indicative of CVE-2026-19669"
author = "valtersit.com"
reference = "https://nvd.nist.gov/vuln/detail/CVE-2026-19669"
date = "2026-01-01"
severity = "high"
strings:
$f1 = "z_vrfy_fuel_gauge_get_props" ascii
$f2 = "z_vrfy_fuel_gauge_set_props" ascii
$f3 = "k_usermode_from_copy" ascii
$f4 = "fuel_gauge_syscall_handlers.c" ascii
$v1 = "k_vals[len]" ascii
$v2 = "k_props[len]" ascii
condition:
(2 of ($f*)) and ($f3 or $f4) and (($v1 and $v2) or any of ($f1, $f2))
}
Suricata IDS Rule
alert tcp any any -> any any (msg:"CVE-2026-19669 Zephyr Fuel Gauge Oversized Syscall Len Potential Exploit"; flow:to_server; content:"fuel_gauge_"; nocase; content:"set_props"; nocase; distance:0; threshold: type both, track by_src, count 5, seconds 60; classtype:attempted-admin; reference:cve,2026-19669; reference:url,nvd.nist.gov/vuln/detail/CVE-2026-19669; sid:2026019669; rev:1;)
Note: this CVE is a local syscall-boundary flaw, so network-side detection is only viable where fuel-gauge operations are tunneled over a request/response protocol; the rule is a heuristic monitoring aid, not a reliable exploit signature.
Elastic Detection
// EQL — host-side collection of Zephyr device logs / crash telemetry
sequence by host.id, process.name
[ any where event.category == "process" and process.command_line : "*fuel_gauge_*" ]
[ any where (event.action == "kernel_fault" or event.reason : "*stack*" or message : "*kernel fault*" or message : "*memory corruption*")
and not process.name in ("known_maintenance","provisioning_tool") ]
Splunk SPL Query
index=device_logs (sourcetype=zephyr:* OR sourcetype=embedded:*)
| search ("z_vrfy_fuel_gauge_get_props" OR "z_vrfy_fuel_gauge_set_props" OR "fuel_gauge_get_props" OR "fuel_gauge_set_props")
| eval suspicious=if(match(_raw,"(?i)(stack.?overflow|kernel fault|memory corruption|oops|privileged stack)"),1,0)
| where suspicious=1
| stats count min(_time) as first_seen max(_time) as last_seen by host, source
| where count >= 1
| convert ctime(first_seen) ctime(last_seen)
Wazuh OSSEC Rule
<group name="zephyr,embedded,cve-2026-19669,">
<rule id="202619690" level="12">
<decoded_as>syslog</decoded_as>
<match>z_vrfy_fuel_gauge_get_props|z_vrfy_fuel_gauge_set_props|fuel_gauge_get_props|fuel_gauge_set_props</match>
<description>CVE-2026-19669: Zephyr fuel gauge syscall invocation observed on $(hostname)</description>
<mitre>
<id>T1068</id>
</mitre>
</rule>
<rule id="202619691" level="15">
<if_sid>202619690</if_sid>
<match>stack overflow|kernel fault|memory corruption|privileged stack</match>
<description>CVE-2026-19669: Possible kernel stack corruption via oversized fuel gauge syscall len on $(hostname)</description>
<mitre>
<id>T1068</id>
</mitre>
</rule>
</group>
Mitigation & Patch Guidance
Patch confidence: 0/4 (UNPATCHED — no patch evidence from any tracked source). No affected-version matrix, OSV packages, or vendor advisory was supplied. The following guidance is derived from the vulnerability description.
1) Immediate mitigations (until a fix is available):
- Disable the fuel-gauge driver syscall handlers, or compile out
CONFIG_USERSPACE(or the fuel-gauge driver) on builds where they are not strictly required. Removing the syscall surface removes the attack primitive. - Remove fuel-gauge device object grants from untrusted user-mode threads. If no thread holds a fuel-gauge object handle, the attacker cannot reach the
k_usermode_from_copy()OOB write path — though the stack-pointer displacement path may still be reachable when the device handler is compiled in. - Increase
CONFIG_PRIVILEGED_STACK_SIZEwell above its 1024-byte default to raise the trigger threshold (len ≈ 170 today). This is defense-in-depth only and does not eliminate the flaw, sincelenis unbounded. - Enable fault handling, watchdog, and memory-protection (MPU) monitoring so that stack-clash-style corruption is at least detected/logged and the device fails safely rather than silently.
- Restrict the ability of user-mode threads to obtain fuel-gauge object handles; treat object-grant configuration as a security control.
2) Patch/upgrade steps: No patch is available from any tracked source. Track the Zephyr project's security advisories and Git history for drivers/fuel_gauge/fuel_gauge_syscall_handlers.c. When a fix lands, the expected remediation pattern is to validate len against a kernel-defined maximum before any VLA allocation (i.e., before K_SYSCALL_DRIVER_FUEL_GAUGE() and before k_usermode_from_copy()), and to eliminate attacker-sized VLAs from the verifier entirely. Until then, do not deploy user-mode fuel-gauge access to untrusted code.
3) Long-term hardening:
- Adopt a rule that no syscall verifier allocates by attacker-controlled size before validation; enforce it in code review and CI (static analysis for VLAs sized by syscall arguments).
- Enable compiler stack-clash protection (
-fstack-clash-protection) where the toolchain supports it, so large stack-pointer displacement faults deterministically. - Reduce
CONFIG_PRIVILEGED_STACK_SIZE-adjacent blast radius with MPU-separated privileged stacks and guard regions; audit all VLA use in syscall verifiers, not just fuel-gauge. - Maintain a system inventory of CONFIG_USERSPACE deployments and object grants, and add device crash/telemetry collection so kernel stack corruption is captured rather than silently lost.
References
- NVD — CVE-2026-19669: https://nvd.nist.gov/vuln/detail/CVE-2026-19669
- CWE-787, Out-of-bounds Write: https://cwe.mitre.org/data/definitions/787.html
- Zephyr Project documentation — Syscalls and CONFIG_USERSPACE: https://docs.zephyrproject.org/
- Zephyr Project Security / vulnerability reporting: https://www.zephyrproject.org/security/
- FIRST — CVSS v3.1 specification (vector CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H): https://www.first.org/cvss/v3.1/specification-document
Threat actor / exploitation evidence: no CISA KEV entry, no EPSS score (not yet scored by FIRST.org), no public PoC, exploit code, or Nuclei template, and no observed campaigns are associated with CVE-2026-19669 at this time.
What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.