CVE-2026-16664: Unchecked serial-recovery image index causes out-of-bounds slot-table read in MCUboot Zephyr port
MCUboot's Zephyr serial-recovery upload handler bsupload() in boot/bootserial/src/bootserial.c decodes the host-supplied image field of an MCUmgr image-upload request into imgnum (a full 32-bit value) and latches it on the off == 0 packet without any range check. It then passes imgnum straight to flashareaidfrommultiimageslot(imgnum, 0), which on the Zephyr port resolves to flashareaidsforslot() in boot/zephyr/include/sysflash/sysflash.h and indexes the static const int allslots[] table as allslots[imgnum 2]. That table holds only MCUBOOTIMAGENUMBER 2 entries, so any imgnum >= MCUBOOTIMAGENUMBER is an out-of-bounds read.
The path is reachable by anyone with access to the serial / SMP recovery console, which is unauthenticated by design, and the bad value is supplied before any image signature is verified. The defect is specific to the default non-direct upload path (MCUBOOTSERIALDIRECTIMAGEUPLOAD disabled) on the Zephyr port with the array-backed slot layout (not CONFIGSINGLEAPPLICATIONSLOT). It is not gated on a multi-image configuration: MCUBOOTIMAGENUMBER defaults to 1, so even a default single-image build is affected for any image >= 1. The MCUBOOTSERIALDIRECTIMAGEUPLOAD path is safe (its flashareaidfromdirectimage() switch returns -EINVAL for unknown indices).
flashareaidfrommultiimageslot() takes a signed int imageindex while imgnum is uint32t, so the attacker controls the sign of the index as well as its magnitude: an image of 0xFFFFFFFF converts to -1 and reads allslots[-2], off the front of the table, while large positive values read off the end (CWE-192). Either way the index multiply img 2 is performed in int, so a wild offset yields a bus/hard fault, giving a reliable denial of service of the bootloader during recovery. For moderately out-of-range indices the read returns adjacent .rodata as a garbage flash-area id that is handed to flashareaopen(); this normally fails with MGMTERREINVAL, but if the garbage id happens to match a valid non-image partition, the subsequent erase/write can target a partition outside the image set (CWE-787). The attacker-supplied value is never echoed back, so there is no information disclosure. The fix is to reject imgnum >= BOOTIMAGENUMBER on the off == 0 packet, before the slot lookup. The comparison must be made on the unsigned imgnum: an equivalent guard applied after the conversion to int would not reject the negative case above. flashareaidsforslot() should bounds-check its own arguments as defence in depth. This vulnerability was reported independently twice: by NVIDIA Project Vanessa on 2026-06-22, and by Kai Phan (@kaimandalic) on 2026-07-19 as GHSA-8v33-88p6-jffj, which is closed as a duplicate of this advisory. Both original reports are reproduced in full below.
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Compensating control
In the Zephyr port's default non-direct serial-recovery upload path, reject the unsigned img_num when img_num >= BOOT_IMAGE_NUMBER on the off == 0 packet before calling flash_area_id_from_multi_image_slot(); also bounds-check arguments inside __flash_area_ids_for_slot() as defense in depth.
Event History
Frequently Asked Questions
Who can reach the vulnerable handler?
Anyone with access to the device's serial or SMP recovery console can reach it. The recovery console is unauthenticated by design, so no prior privileges are required.
What does an attacker need to send?
The attacker must send an MCUmgr image-upload request with an out-of-range image field on the packet whose offset is zero. The invalid image value is processed before any image signature verification occurs.
Are default single-image Zephyr builds affected?
Yes. The issue is not limited to multi-image builds: MCUBOOT_IMAGE_NUMBER defaults to 1, so a default single-image build is affected when an image number of 1 or greater is supplied, provided the other affected configuration conditions apply.
Which configurations are outside the affected path?
The issue is specific to the Zephyr port using the array-backed slot layout and the non-direct upload path, with MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD disabled. CONFIG_SINGLE_APPLICATION_SLOT is not affected by this array-backed slot-table access.
How can I determine whether a build is exposed?
Check whether the build uses the Zephyr port, exposes serial or SMP recovery upload, has MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD disabled, and does not use CONFIG_SINGLE_APPLICATION_SLOT. In that configuration, image-upload requests with image numbers at or above MCUBOOT_IMAGE_NUMBER exercise the out-of-bounds lookup.