CVE-2026-16662 (GCVE-0-2026-16662)

Vulnerability from cvelistv5 – Published: 2026-11-13 00:23 – Updated: 2026-11-13 21:59
VLAI
Title
Uninitialised bootloader stack disclosed into the measured-boot attestation record via a short EXPECTED_HASH TLV in MCUboot
Summary
boot_save_boot_status() in boot/bootutil/src/boot_record.c reads the image's EXPECTED_HASH_TLV into a stack buffer image_hash[IMAGE_HASH_SIZE] that is never zero-initialised. The TLV handler validates only the upper bound (len > sizeof(image_hash)) and then reads exactly len bytes, so a TLV shorter than IMAGE_HASH_SIZE leaves the tail of image_hash holding stale stack content. The subsequent copy into the boot record, memcpy(buf + offset, image_hash, sizeof(image_hash)), uses the fixed buffer size rather than len, so up to IMAGE_HASH_SIZE - 1 bytes of uninitialised bootloader stack are written into the measured-boot record. The defect is reachable only under MCUBOOT_MEASURED_BOOT, and only when nothing has checked the length of the hash TLV before boot_save_boot_status() reads it. bootutil_img_validate() rejects a hash TLV whose length is not exactly sizeof(hash) (boot/bootutil/src/image_validate.c:345), and primary-slot validation is on by default (Zephyr's CONFIG_BOOT_VALIDATE_SLOT0 defaults to y), so in a default build the malformed image never reaches this code. Two kinds of build let a short TLV through: Builds that use pure signatures (MCUBOOT_SIGN_PURE, Zephyr CONFIG_BOOT_SIGNATURE_TYPE_PURE). The signature covers the image itself, so the hash-TLV check in bootutil_img_validate() is compiled out, and a pure-signed image normally carries no hash TLV. A hash TLV is still allowed in the unprotected TLV area, which the signature does not cover, so a short one can be added to a correctly signed image without invalidating it. This applies with every upgrade strategy, including direct-XIP and RAM-load, and the modified image can be delivered through any path that accepts a signed image. Builds with primary-slot validation turned off: the swap and overwrite loader built without MCUBOOT_VALIDATE_PRIMARY_SLOT, which checks only the image magic before calling boot_add_shared_data(), and the Zephyr single-slot loader (boot/zephyr/single_loader.c) built without it, including the MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE variant, which skips validation once the trailer records an earlier successful one. Placing the crafted image requires physical or flash-write access to the device; in a single-slot build with serial recovery enabled, the serial-recovery upload writes the primary slot directly and can place it as well. Outside pure-signature builds, the direct-XIP and RAM-load strategies in boot/bootutil/src/loader.c validate the selected slot unconditionally and are not affected. It is also reachable through a time-of-check/time-of-use change to tamperable external flash between validation and the boot-record read. In these configurations the boot record's measurement is already not trustworthy: the hash copied into the record is the image's own EXPECTED_HASH_TLV, which nothing has verified and which the attacker chooses. The defect therefore does not weaken attestation integrity any further. What it adds is a path for bootloader memory to leave the device: up to 63 bytes (IMAGE_HASH_SIZE - 1) of uninitialised bootloader stack are embedded in the measurement field that a downstream attestation service sends to a remote verifier. In the configurations analysed the residue is bootloader internal state (TLV offsets and lengths, flash addresses, loop state), not key material, but what occupies that stack region depends on configuration and on which code ran before boot_save_boot_status(). It is reported as a low-severity, defense-in-depth disclosure with no integrity or availability impact. This is distinct from the already-fixed record_len integer underflow in the same routine (GHSA-8hrv-4cp5-4rg3). The fix rejects any EXPECTED_HASH_TLV whose length is not exactly IMAGE_HASH_SIZE.
CWE
Assigner
zephyr CNA under the mitre root
CNA scorecard B 77/100 over 238 records in the last 180 days details
Impacted products
Vendor Product Version CPE status
mcu-tools mcuboot Affected: 1.6.0 , < 2.5.0 (semver)
guessed Create a notification for this product.
Show details on NVD website

{
  "containers": {
    "cna": {
      "affected": [
        {
          "collectionURL": "https://github.com/mcu-tools/mcuboot",
          "defaultStatus": "unaffected",
          "packageName": "mcuboot",
          "product": "mcuboot",
          "programFiles": [
            "boot/bootutil/src/boot_record.c"
          ],
          "programRoutines": [
            {
              "name": "boot_save_boot_status"
            }
          ],
          "vendor": "mcu-tools",
          "versions": [
            {
              "lessThan": "2.5.0",
              "status": "affected",
              "version": "1.6.0",
              "versionType": "semver"
            }
          ]
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "boot_save_boot_status() in boot/bootutil/src/boot_record.c reads the image\u0027s EXPECTED_HASH_TLV into a stack buffer image_hash[IMAGE_HASH_SIZE] that is never zero-initialised. The TLV handler validates only the upper bound (len \u003e sizeof(image_hash)) and then reads exactly len bytes, so a TLV shorter than IMAGE_HASH_SIZE leaves the tail of image_hash holding stale stack content. The subsequent copy into the boot record, memcpy(buf + offset, image_hash, sizeof(image_hash)), uses the fixed buffer size rather than len, so up to IMAGE_HASH_SIZE - 1 bytes of uninitialised bootloader stack are written into the measured-boot record.\n\nThe defect is reachable only under MCUBOOT_MEASURED_BOOT, and only when nothing has checked the length of the hash TLV before boot_save_boot_status() reads it. bootutil_img_validate() rejects a hash TLV whose length is not exactly sizeof(hash) (boot/bootutil/src/image_validate.c:345), and primary-slot validation is on by default (Zephyr\u0027s CONFIG_BOOT_VALIDATE_SLOT0 defaults to y), so in a default build the malformed image never reaches this code. Two kinds of build let a short TLV through:\n\nBuilds that use pure signatures (MCUBOOT_SIGN_PURE, Zephyr CONFIG_BOOT_SIGNATURE_TYPE_PURE). The signature covers the image itself, so the hash-TLV check in bootutil_img_validate() is compiled out, and a pure-signed image normally carries no hash TLV. A hash TLV is still allowed in the unprotected TLV area, which the signature does not cover, so a short one can be added to a correctly signed image without invalidating it. This applies with every upgrade strategy, including direct-XIP and RAM-load, and the modified image can be delivered through any path that accepts a signed image.\nBuilds with primary-slot validation turned off: the swap and overwrite loader built without MCUBOOT_VALIDATE_PRIMARY_SLOT, which checks only the image magic before calling boot_add_shared_data(), and the Zephyr single-slot loader (boot/zephyr/single_loader.c) built without it, including the MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE variant, which skips validation once the trailer records an earlier successful one. Placing the crafted image requires physical or flash-write access to the device; in a single-slot build with serial recovery enabled, the serial-recovery upload writes the primary slot directly and can place it as well. Outside pure-signature builds, the direct-XIP and RAM-load strategies in boot/bootutil/src/loader.c validate the selected slot unconditionally and are not affected.\n\nIt is also reachable through a time-of-check/time-of-use change to tamperable external flash between validation and the boot-record read.\n\nIn these configurations the boot record\u0027s measurement is already not trustworthy: the hash copied into the record is the image\u0027s own EXPECTED_HASH_TLV, which nothing has verified and which the attacker chooses. The defect therefore does not weaken attestation integrity any further. What it adds is a path for bootloader memory to leave the device: up to 63 bytes (IMAGE_HASH_SIZE - 1) of uninitialised bootloader stack are embedded in the measurement field that a downstream attestation service sends to a remote verifier. In the configurations analysed the residue is bootloader internal state (TLV offsets and lengths, flash addresses, loop state), not key material, but what occupies that stack region depends on configuration and on which code ran before boot_save_boot_status(). It is reported as a low-severity, defense-in-depth disclosure with no integrity or availability impact.\n\nThis is distinct from the already-fixed record_len integer underflow in the same routine (GHSA-8hrv-4cp5-4rg3). The fix rejects any EXPECTED_HASH_TLV whose length is not exactly IMAGE_HASH_SIZE."
        }
      ],
      "metrics": [
        {
          "cvssV3_1": {
            "baseScore": 2.4,
            "baseSeverity": "LOW",
            "vectorString": "CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
            "version": "3.1"
          },
          "format": "CVSS"
        }
      ],
      "problemTypes": [
        {
          "descriptions": [
            {
              "cweId": "CWE-457",
              "description": "info-leak",
              "lang": "en",
              "type": "CWE"
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-11-13T21:59:04.545Z",
        "orgId": "e2e69745-5e70-4e92-8431-deb5529a81ad",
        "shortName": "zephyr"
      },
      "references": [
        {
          "name": "Fix commit",
          "tags": [
            "patch"
          ],
          "url": "https://github.com/mcu-tools/mcuboot/commit/5098d8eef1139abd3d821d8138a6321d656dcd3e"
        },
        {
          "name": "GHSA-779w-4x76-5chf",
          "url": "https://github.com/mcu-tools/mcuboot/security/advisories/GHSA-779w-4x76-5chf"
        }
      ],
      "title": "Uninitialised bootloader stack disclosed into the measured-boot attestation record via a short EXPECTED_HASH TLV in MCUboot",
      "x_generator": {
        "engine": "cvelib 1.8.0"
      }
    }
  },
  "cveMetadata": {
    "assignerOrgId": "e2e69745-5e70-4e92-8431-deb5529a81ad",
    "assignerShortName": "zephyr",
    "cveId": "CVE-2026-16662",
    "datePublished": "2026-11-13T00:23:00.336Z",
    "dateReserved": "2026-07-22T19:47:52.428Z",
    "dateUpdated": "2026-11-13T21:59:04.545Z",
    "state": "PUBLISHED"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2",
  "vulnerability-lookup:meta": {
    "epss": {
      "cve": "CVE-2026-16662",
      "date": "2026-11-13",
      "epss": "0.00137",
      "percentile": "0.03173"
    },
    "nvd": {
      "cve": {
        "affected": [
          {
            "affectedData": [
              {
                "collectionURL": "https://github.com/mcu-tools/mcuboot",
                "defaultStatus": "unaffected",
                "packageName": "mcuboot",
                "product": "mcuboot",
                "programFiles": [
                  "boot/bootutil/src/boot_record.c"
                ],
                "programRoutines": [
                  {
                    "name": "boot_save_boot_status"
                  }
                ],
                "vendor": "mcu-tools",
                "versions": [
                  {
                    "lessThan": "2.5.0",
                    "status": "affected",
                    "version": "1.6.0",
                    "versionType": "semver"
                  }
                ]
              }
            ],
            "source": "vulnerabilities@zephyrproject.org"
          }
        ],
        "cveTags": [],
        "descriptions": [
          {
            "lang": "en",
            "value": "boot_save_boot_status() in boot/bootutil/src/boot_record.c reads the image\u0027s EXPECTED_HASH_TLV into a stack buffer image_hash[IMAGE_HASH_SIZE] that is never zero-initialised. The TLV handler validates only the upper bound (len \u003e sizeof(image_hash)) and then reads exactly len bytes, so a TLV shorter than IMAGE_HASH_SIZE leaves the tail of image_hash holding stale stack content. The subsequent copy into the boot record, memcpy(buf + offset, image_hash, sizeof(image_hash)), uses the fixed buffer size rather than len, so up to IMAGE_HASH_SIZE - 1 bytes of uninitialised bootloader stack are written into the measured-boot record.\n\nThe defect is reachable only under MCUBOOT_MEASURED_BOOT, and only when nothing has checked the length of the hash TLV before boot_save_boot_status() reads it. bootutil_img_validate() rejects a hash TLV whose length is not exactly sizeof(hash) (boot/bootutil/src/image_validate.c:345), and primary-slot validation is on by default (Zephyr\u0027s CONFIG_BOOT_VALIDATE_SLOT0 defaults to y), so in a default build the malformed image never reaches this code. Two kinds of build let a short TLV through:\n\nBuilds that use pure signatures (MCUBOOT_SIGN_PURE, Zephyr CONFIG_BOOT_SIGNATURE_TYPE_PURE). The signature covers the image itself, so the hash-TLV check in bootutil_img_validate() is compiled out, and a pure-signed image normally carries no hash TLV. A hash TLV is still allowed in the unprotected TLV area, which the signature does not cover, so a short one can be added to a correctly signed image without invalidating it. This applies with every upgrade strategy, including direct-XIP and RAM-load, and the modified image can be delivered through any path that accepts a signed image.\nBuilds with primary-slot validation turned off: the swap and overwrite loader built without MCUBOOT_VALIDATE_PRIMARY_SLOT, which checks only the image magic before calling boot_add_shared_data(), and the Zephyr single-slot loader (boot/zephyr/single_loader.c) built without it, including the MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE variant, which skips validation once the trailer records an earlier successful one. Placing the crafted image requires physical or flash-write access to the device; in a single-slot build with serial recovery enabled, the serial-recovery upload writes the primary slot directly and can place it as well. Outside pure-signature builds, the direct-XIP and RAM-load strategies in boot/bootutil/src/loader.c validate the selected slot unconditionally and are not affected.\n\nIt is also reachable through a time-of-check/time-of-use change to tamperable external flash between validation and the boot-record read.\n\nIn these configurations the boot record\u0027s measurement is already not trustworthy: the hash copied into the record is the image\u0027s own EXPECTED_HASH_TLV, which nothing has verified and which the attacker chooses. The defect therefore does not weaken attestation integrity any further. What it adds is a path for bootloader memory to leave the device: up to 63 bytes (IMAGE_HASH_SIZE - 1) of uninitialised bootloader stack are embedded in the measurement field that a downstream attestation service sends to a remote verifier. In the configurations analysed the residue is bootloader internal state (TLV offsets and lengths, flash addresses, loop state), not key material, but what occupies that stack region depends on configuration and on which code ran before boot_save_boot_status(). It is reported as a low-severity, defense-in-depth disclosure with no integrity or availability impact.\n\nThis is distinct from the already-fixed record_len integer underflow in the same routine (GHSA-8hrv-4cp5-4rg3). The fix rejects any EXPECTED_HASH_TLV whose length is not exactly IMAGE_HASH_SIZE."
          }
        ],
        "id": "CVE-2026-16662",
        "lastModified": "2026-11-13T22:17:24.893",
        "metrics": {
          "cvssMetricV31": [
            {
              "cvssData": {
                "attackComplexity": "LOW",
                "attackVector": "PHYSICAL",
                "availabilityImpact": "NONE",
                "baseScore": 2.4,
                "baseSeverity": "LOW",
                "confidentialityImpact": "LOW",
                "integrityImpact": "NONE",
                "privilegesRequired": "NONE",
                "scope": "UNCHANGED",
                "userInteraction": "NONE",
                "vectorString": "CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
                "version": "3.1"
              },
              "exploitabilityScore": 0.9,
              "impactScore": 1.4,
              "source": "vulnerabilities@zephyrproject.org",
              "type": "Secondary"
            }
          ]
        },
        "published": "2026-11-13T02:18:57.027",
        "references": [
          {
            "source": "vulnerabilities@zephyrproject.org",
            "url": "https://github.com/mcu-tools/mcuboot/commit/5098d8eef1139abd3d821d8138a6321d656dcd3e"
          },
          {
            "source": "vulnerabilities@zephyrproject.org",
            "url": "https://github.com/mcu-tools/mcuboot/security/advisories/GHSA-779w-4x76-5chf"
          }
        ],
        "sourceIdentifier": "vulnerabilities@zephyrproject.org",
        "vulnStatus": "Awaiting Analysis",
        "weaknesses": [
          {
            "description": [
              {
                "lang": "en",
                "value": "CWE-457"
              }
            ],
            "source": "vulnerabilities@zephyrproject.org",
            "type": "Secondary"
          }
        ]
      }
    }
  }
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline

Sightings and recorded dates, grouped by day · UTC

JSON
How durations are calculated

Following the VTEM framework (Black Hat USA 2015), time to patch starts when the vendor or a coordinator was informed, total time to patch at discovery, and disclosure to patch at public disclosure; vendor response time runs from the report to its acknowledgement. Time to exploit and time unpatched start at the earliest discovery or report, falling back to public disclosure. Unpatched time ends at the first recorded patch, or the calculation time when no patch is recorded. Exploitation to patch shows the interval between those two events; a published proof of concept is a public exploit, not exploitation.

Each result shows its source dates. A negative interval means the end event came first; when date-only inputs leave the order open, the result says so. Date-only inputs are approximate. The earliest evidence wins: KEV report dates and sightings are labelled as such. Records describing another vulnerability are listed but never calculated from, and a PoC alone does not establish exploitation. Missing patch evidence does not prove that no patch exists. Filters below change the event list only.

Events included in the timeline

Loading timeline…


    Loading…

    Loading…

    Loading…

    Related by attack behaviour

    Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.