# CVE-2026-16664: Unchecked serial-recovery image index causes out-of-bounds slot-table read in MCUboot Zephyr port

Status: published. Published: 2026-11-13. Updated: 2026-11-13.

MCUboot's Zephyr serial-recovery upload handler bs_upload() in boot/boot_serial/src/boot_serial.c decodes the host-supplied image field of an MCUmgr image-upload request into img_num (a full 32-bit value) and latches it on the off == 0 packet without any range check. It then passes img_num straight to flash_area_id_from_multi_image_slot(img_num, 0), which on the Zephyr port resolves to __flash_area_ids_for_slot() in boot/zephyr/include/sysflash/sysflash.h and indexes the static const int all_slots[] table as all_slots[img_num  2]. That table holds only MCUBOOT_IMAGE_NUMBER  2 entries, so any img_num >= MCUBOOT_IMAGE_NUMBER 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 (MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD disabled) on the Zephyr port with the array-backed slot layout (not CONFIG_SINGLE_APPLICATION_SLOT). It is not gated on a multi-image configuration: MCUBOOT_IMAGE_NUMBER defaults to 1, so even a default single-image build is affected for any image >= 1. The MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD path is safe (its flash_area_id_from_direct_image() switch returns -EINVAL for unknown indices).

flash_area_id_from_multi_image_slot() takes a signed int image_index while img_num is uint32_t, so the attacker controls the sign of the index as well as its magnitude: an image of 0xFFFFFFFF converts to -1 and reads all_slots[-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 flash_area_open(); this normally fails with MGMT_ERR_EINVAL, 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 img_num >= BOOT_IMAGE_NUMBER on the off == 0 packet, before the slot lookup. The comparison must be made on the unsigned img_num: an equivalent guard applied after the conversion to int would not reject the negative case above. __flash_area_ids_for_slot() 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

- fix: The reporting source identifies this reference as a patch. Check the advisory for affected versions and supported release branches. (source: CNA: zephyr) — https://github.com/mcu-tools/mcuboot/commit/183a05f256bdbbac86edcb048958da59018f814e

## Affected products and versions

- mcu-tools / mcuboot (mcuboot): ≥ 2.0.0; ≤ * (affected, semver). Source: CNA: zephyr

## Severity and prioritization

- CVSS 3.1: 5.1 (medium); CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L; source: CNA: zephyr

- CISA KEV: No listing in collected sources

- EPSS: Not available

- SSVC: Not available

- Weaknesses: CWE-129

## Exploit evidence

No exploit evidence in collected sources. This is not proof of no exploitation.

## References

- https://github.com/mcu-tools/mcuboot/commit/183a05f256bdbbac86edcb048958da59018f814e (CNA: zephyr; patch)

- https://github.com/mcu-tools/mcuboot/security/advisories/GHSA-8rcq-2mgr-fhp8 (CNA: zephyr)

## Provenance

- CNA: zephyr: https://www.cve.org/CVERecord?id=CVE-2026-16664; retrieved 2026-11-13; source updated 2026-11-13

Revision: 1da5c8f57563858890016d116d8cfba40b57c786ea974ea70fac069c59f156f6

Canonical: https://y2.dev/cve/CVE-2026-16664

## Agent and API access

Public CVE pages, Markdown, and JSON are free to read without an account or API key.

- Public catalog: https://y2.dev/cve/index.json. Follow nextCursor with the same search, filters, sort, and limit (1–100). A null cursor marks the end.

- WebMCP: search_cve_disclosures, get_cve_disclosure, get_cve_page_markdown, get_y2_cve_access. Available in compatible browsers.

- Cyber API: https://api.y2.dev/api/v2/cyber/cves and https://api.y2.dev/api/v2/cyber/cves/{cveId}.

- Y2 Pro or Elite: create a workspace API key with the intel:cyber scope and send Authorization: Bearer <Y2_API_KEY>. Setup: https://y2.dev/docs/api/create-key.

- x402: Pay per request without an account or API key. Omit Authorization, read the HTTP 402 PAYMENT-REQUIRED challenge, validate its current requirements, and retry with PAYMENT-SIGNATURE through an authorized payment client. These browser tools never make payments. Guide: https://y2.dev/docs/api/x402.

- OpenAPI: https://y2.dev/api/openapi.yaml. Agent access metadata: https://y2.dev/cve/agent.json.

Collected public records only. Check source status for coverage and freshness.