CVE-2026-16147 Overview
CVE-2026-16147 is a use-after-free vulnerability [CWE-416] in the Zephyr RTOS ITE IT82xx2 USB device-controller driver (drivers/usb/udc/udc_it82xx2.c). The driver mishandles multi-packet OUT transfers on non-control endpoints, submitting the active transfer buffer to the upper USB stack before it is fully filled. Once submitted, the buffer's ownership transfers to the stack, which may free and recycle it while the controller continues DMA writes from the untrusted host. The flaw yields a device-side kernel heap corruption primitive over physical USB attach.
Critical Impact
A malicious USB host can trigger kernel heap use-after-free writes and double net_buf_unref() on any non-control OUT endpoint, causing denial of service and potential adjacent memory corruption.
Affected Products
- Zephyr RTOS drivers/usb/udc/udc_it82xx2.c (ITE IT82xx2 USB device controller driver)
- Devices using the ITE IT82xx2 USB peripheral controller with the Zephyr USB device stack
- Bulk/interrupt OUT endpoints queuing buffers larger than one max-packet-size
Discovery Timeline
- 2026-09-14 - CVE-2026-16147 published to NVD
- 2026-09-14 - Last updated in NVD database
Technical Details for CVE-2026-16147
Vulnerability Analysis
The defect resides in work_handler_out(). The routine obtains the active transfer buffer via udc_buf_peek(), which does not dequeue it from the endpoint. When a full max-packet-size packet arrives and the buffer still has tailroom, the pre-fix code re-arms the endpoint via work_handler_xfer_continue() while simultaneously calling udc_submit_ep_event() on the same buffer.
udc_submit_ep_event() transfers ownership of the buffer to the USB device stack. The class handler subsequently processes the buffer and calls net_buf_unref(), potentially freeing it. Meanwhile, the IT82xx2 controller continues to DMA host-controlled OUT packets into that same memory, producing a use-after-free write with attacker-controlled bytes.
Because the buffer was never dequeued, the completing packet path invokes udc_buf_get() on the same object and submits it a second time. This appends &buf->node to the uds_ctx->ep_events singly-linked list twice, corrupting the list, and triggers a double net_buf_unref().
Root Cause
The root cause is premature ownership transfer of a partially filled DMA buffer. The driver assumed submission and continuation were compatible operations for non-control endpoints, but the USB device stack treats submission as a handoff. The absence of a dequeue step compounds the flaw by allowing a second submission of the same object.
Attack Vector
The vector is physical USB attach. The IT82xx2 is a USB peripheral controller, so an untrusted USB host fully controls OUT-transfer packetization. Any non-control OUT endpoint whose queued buffer exceeds one packet, an ordinary bulk or interrupt pattern, can be forced into the vulnerable path. The driver and stack execute in kernel context, giving the external host a device-side kernel heap-corruption primitive.
// Patch: drivers/usb/udc/udc_it82xx2.c - defer OUT event until buffer is complete
LOG_DBG("Handle data OUT, %zu | %zu", len, net_buf_tailroom(buf));
+ if (ep != USB_CONTROL_EP_OUT) {
+ atomic_clear_bit(&priv->out_fifo_state, IT82xx2_STATE_OUT_SHARED_FIFO_BUSY);
+ }
+
+ udc_ep_set_busy(ep_cfg, false);
+
if (net_buf_tailroom(buf) && len == udc_mps_ep_size(ep_cfg)) {
- work_handler_xfer_continue(dev, ep, buf);
- if (ep != USB_CONTROL_EP_OUT) {
- err = udc_submit_ep_event(dev, buf, 0);
+ /* For non-control endpoints, the next out transfer will be started outside
+ * this function. Do nothing here to avoid triggering it twice.
+ */
+ if (ep == USB_CONTROL_EP_OUT) {
+ work_handler_xfer_continue(dev, ep, buf);
}
- return err;
+
+ return 0;
}
buf = udc_buf_get(ep_cfg);
if (buf == NULL) {
return -ENODATA;
}
- udc_ep_set_busy(ep_cfg, false);
Source: Zephyr commit 2abc3088a6598579cf322452801a13cb0ec57b0e. The fix defers submission until the buffer is completely filled and lets xfer_work_handler() drive continuation, ensuring each OUT buffer is submitted to the upper stack exactly once.
Detection Methods for CVE-2026-16147
Indicators of Compromise
- Kernel panics or hard faults in the USB work queue thread shortly after device enumeration or bulk/interrupt OUT traffic.
- net_buf pool corruption warnings, double-unref assertions, or slist integrity failures logged by the Zephyr USB stack.
- Unexpected reboots or watchdog resets on ITE IT82xx2-based devices when connected to unknown USB hosts.
Detection Strategies
- Audit firmware images for the presence of udc_it82xx2.c and verify whether the patched submission ordering is included.
- Enable Zephyr's CONFIG_NET_BUF_LOG and CONFIG_ASSERT in test builds to catch double-unref and list corruption during fuzzing.
- Fuzz OUT endpoints with a programmable USB host (for example, Facedancer or a Linux gadget) that sends full max-packet-size packets followed by short packets across bulk and interrupt endpoints.
Monitoring Recommendations
- Monitor device serial and RTT logs for repeated USB reset, enumeration errors, or -ENODATA returns from work_handler_out().
- Track physical access to affected devices; the vulnerability requires a USB host connection.
- Correlate device crash telemetry with USB attach events in fleet management systems.
How to Mitigate CVE-2026-16147
Immediate Actions Required
- Rebuild and reflash affected firmware with the upstream Zephyr fix applied to drivers/usb/udc/udc_it82xx2.c.
- Restrict physical USB access on production devices using the IT82xx2 controller until patched firmware is deployed.
- Inventory all products and prototypes based on the ITE IT82xx2 USB peripheral controller and identify their Zephyr version.
Patch Information
Apply Zephyr commit 2abc3088a6598579cf322452801a13cb0ec57b0e, referenced in GHSA-3q4g-7w6j-8qfp. The patch defers udc_submit_ep_event() for non-control OUT endpoints until the transfer buffer is fully filled, and lets xfer_work_handler() drive continuation so each buffer is submitted exactly once.
Workarounds
- Disable non-control OUT endpoints on the IT82xx2 controller if the device function permits it.
- Configure USB class drivers to queue OUT buffers no larger than one max-packet-size, preventing the multi-packet path from executing.
- Enclose devices in tamper-resistant housings that prevent unauthorized USB host connections.
# Fetch and cherry-pick the upstream fix into a Zephyr workspace
cd zephyr
git fetch origin
git cherry-pick 2abc3088a6598579cf322452801a13cb0ec57b0e
west build -b <your_it82xx2_board> -p auto samples/subsys/usb/<your_sample>
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

