CVE-2026-19676 Overview
CVE-2026-19676 is a kernel memory corruption vulnerability in the Zephyr RTOS Platform Environment Control Interface (PECI) subsystem. The user-mode verifier z_vrfy_peci_transfer() in drivers/peci/peci_handlers.c validates only the outer struct peci_msg and leaves the embedded tx_buffer and rx_buffer pointers caller-controlled. In-tree PECI drivers dereference those pointers in supervisor mode, giving a user-mode thread an arbitrary kernel read and write primitive. The flaw is classified under [CWE-822: Untrusted Pointer Dereference].
Critical Impact
A user-mode application granted the PECI device object can read or write arbitrary kernel memory, escalating to supervisor-mode code execution.
Affected Products
- Zephyr RTOS builds with CONFIG_USERSPACE=y and CONFIG_PECI_NPCX enabled
- Zephyr RTOS builds with CONFIG_USERSPACE=y and CONFIG_PECI_XEC enabled
- Zephyr RTOS builds with CONFIG_USERSPACE=y and CONFIG_PECI_ITE_IT8XXX2 enabled
Discovery Timeline
- 2026-10-21 - CVE-2026-19676 published to NVD
- 2026-10-22 - Last updated in NVD database
Technical Details for CVE-2026-19676
Vulnerability Analysis
The PECI subsystem exposes peci_transfer() as a system call that user-mode threads can invoke after being granted the PECI device object. The verifier calls k_usermode_from_copy() to duplicate the struct peci_msg argument into kernel memory. This copy only duplicates the outer structure. The embedded struct peci_buf members tx_buffer and rx_buffer still carry caller-supplied buf pointers and len values.
Every in-tree PECI driver dereferences those pointers directly in supervisor mode. peci_npcx_transfer() in drivers/peci/peci_npcx.c and peci_it8xxx2_transfer() in drivers/peci/peci_ite_it8xxx2.c copy hardware bytes into rx_buffer.buf[i] and read command bytes out of tx_buffer.buf[i]. peci_xec_read() and peci_xec_write() in drivers/peci/peci_mchp_xec.c perform equivalent accesses with no bound checking on rx_buffer.len.
Root Cause
The verifier failed to apply K_SYSCALL_MEMORY_READ() and K_SYSCALL_MEMORY_WRITE() checks against the embedded buffer pointers. These macros confirm that a user-mode address range is readable or writable from the calling thread. Without them, kernel addresses pass validation unchanged.
Attack Vector
An attacker needs local code execution in a user-mode thread holding the PECI device under CONFIG_USERSPACE. By pointing rx_buffer.buf at kernel structures, the attacker causes the driver to write hardware-supplied bytes into kernel memory. By pointing tx_buffer.buf at kernel memory, the attacker leaks kernel contents onto the PECI or eSPI out-of-band bus where a bus observer can capture them. Supplying an unmapped address triggers a supervisor-mode fault.
K_OOPS(K_SYSCALL_DRIVER_PECI(dev, transfer));
K_OOPS(k_usermode_from_copy(&msg_copy, msg, sizeof(*msg)));
+ /**
+ * k_usermode_from_copy() only duplicates the outer struct; the buffer
+ * pointers it carries are still caller supplied and the driver
+ * dereferences them in supervisor mode, so they must be checked here.
+ */
+ if ((msg_copy.tx_buffer.buf != NULL) && (msg_copy.tx_buffer.len > 1U)) {
+ K_OOPS(K_SYSCALL_MEMORY_READ(msg_copy.tx_buffer.buf,
+ msg_copy.tx_buffer.len - 1U));
+ }
+
+ if (msg_copy.rx_buffer.buf != NULL) {
+ size_t rx_len;
+
+ K_OOPS(K_SYSCALL_VERIFY_MSG(!size_add_overflow(msg_copy.rx_buffer.len,
+ 1U, &rx_len),
+ "rx_buffer.len overflow"));
+ K_OOPS(K_SYSCALL_MEMORY_WRITE(msg_copy.rx_buffer.buf, rx_len));
+ }
+
return z_impl_peci_transfer(dev, &msg_copy);
}
Source: Zephyr Project patch commit d7faf32. The patch adds K_SYSCALL_MEMORY_READ() and K_SYSCALL_MEMORY_WRITE() checks on the embedded buffers and guards the RX length addition with size_add_overflow() to account for the frame-check-sequence byte.
Detection Methods for CVE-2026-19676
Indicators of Compromise
- Unexpected supervisor-mode faults originating from peci_npcx_transfer(), peci_it8xxx2_transfer(), peci_xec_read(), or peci_xec_write()
- PECI bus traffic containing byte sequences that match kernel symbol or stack content
- Repeated peci_transfer() system calls from a single user-mode thread with varying buffer addresses
Detection Strategies
- Audit Zephyr build configurations for the combination of CONFIG_USERSPACE=y with any of CONFIG_PECI_NPCX, CONFIG_PECI_XEC, or CONFIG_PECI_ITE_IT8XXX2
- Review user-mode thread code that holds the PECI device object for buffer pointers originating outside the thread's partition
- Add instrumentation in test builds that logs the resolved address range of tx_buffer.buf and rx_buffer.buf on each call
Monitoring Recommendations
- Capture PECI and eSPI bus traces during security testing to detect kernel-content disclosure
- Alert on crash dumps where the fault PC lies inside a PECI driver transfer routine
- Track firmware versions deployed to baseboard management controllers and server platforms that integrate Zephyr with PECI
How to Mitigate CVE-2026-19676
Immediate Actions Required
- Apply the upstream Zephyr fix in commit d7faf323d52b7e8845a63b1f854a82bdda44c261 and rebuild affected firmware images
- Revoke the PECI device object from user-mode threads that do not require direct hardware access
- Audit downstream forks of Zephyr for backports of the PECI subsystem to confirm the patched verifier is present
Patch Information
The fix is tracked in GitHub Security Advisory GHSA-g66q-frxm-3hfg and merged in Zephyr Project commit d7faf32. The patch adds explicit K_SYSCALL_MEMORY_READ() and K_SYSCALL_MEMORY_WRITE() checks on the embedded tx_buffer and rx_buffer members and guards RX length arithmetic with size_add_overflow().
Workarounds
- Disable the vulnerable PECI drivers by unsetting CONFIG_PECI_NPCX, CONFIG_PECI_XEC, and CONFIG_PECI_ITE_IT8XXX2 where PECI access is not required
- Disable CONFIG_USERSPACE on firmware builds where separation between user-mode and supervisor-mode threads is not needed
- Wrap PECI access behind a trusted supervisor-mode service that validates buffer ownership before invoking the driver
# Remove vulnerable PECI drivers from the Zephyr build configuration
# in prj.conf when PECI functionality is not required
CONFIG_PECI=n
CONFIG_PECI_NPCX=n
CONFIG_PECI_XEC=n
CONFIG_PECI_ITE_IT8XXX2=n
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

