Secure Boot: Eight Mistakes We Keep Finding in Devices
Secure boot fails through configuration more often than cryptography: unburned eFuses, open debug ports, broken chains, no anti-rollback. Eight mistakes and fixes.
Zyberum Security Team · Published · 8 min read
Secure boot rarely fails because the cryptography is wrong. It fails because the chain is incomplete, because a fuse was never burned, because a debug port is still open or because an old, signed firmware can be flashed back. In our hardware and ECU pentests we see the same eight mistakes across consumer devices, appliances, IoT modules and automotive controllers. Here they are, with the fix for each.
1. Implemented, but not enabled
The design document describes secure boot. The bootloader contains the verification code. The eFuse that makes the check mandatory was never burned on the production line, or the device still runs in the development mode that allows unsigned images.
We find this on a regular basis, because enabling secure boot is irreversible and someone in manufacturing or development did not want to be the one to do it. On ESP32-based modules the development mode for flash encryption and secure boot is convenient during bring-up and a liability when it ships.
Fix: a documented production step that burns the fuses and verifies them, plus a check in the end-of-line test that reads the fuse state back. We check production units, never engineering samples.
2. Debug ports still open
JTAG, SWD or a vendor download mode bypass the chain entirely: halt the CPU after verification, patch RAM, or read the key material and the decrypted firmware from memory. On an appliance from a household manufacturer the JTAG port was open while secure boot was on; the boot chain was correct and irrelevant.
Fix: disable or lock the debug interfaces in production (eFuse, debug authentication with a per-device key, read-out protection) and disable the ROM download modes. Verify this on the bench, not in the datasheet.
3. The chain stops too early
The ROM verifies the bootloader, the bootloader verifies the kernel, and then everything else is trusted: the root file system, the application, the device tree, the configuration partition, the firmware on a secondary microcontroller or radio module. A root file system without dm-verity is writable, and a writable file system with an unverified startup script is code execution at every boot.
Fix: extend the chain to every piece of code and configuration that influences behaviour: dm-verity or signed squashfs for Linux, signed application images for microcontrollers, signed configuration or configuration validated against a signed schema, and verification of co-processor firmware by the main controller.
4. No anti-rollback
The signature check passes for every image the vendor ever signed, including the one from two years ago with the known vulnerability. An attacker with a copy of the old update flashes it back and uses the old bug.
Fix: a monotonic version counter in eFuses or a protected storage area that the bootloader compares against the image version, and a policy for when to increment it. On many chips the counter has a limited number of steps, so increment it on security fixes, not on every release.
5. Keys handled like configuration
One signing key for the whole product family, stored on the build server or in the repository. A development key that was never replaced before production. No way to revoke a key once it leaks: on the original ESP32, for example, Secure Boot V2 stores a single public key digest, with no revocation, and several other controllers are similar.
Fix: generate production keys in an HSM or at least on an offline machine, separate development and production keys, choose a chip or a scheme that supports more than one key and revocation, and write down who may sign what.
6. A hash where a signature belongs, or a check at the wrong moment
Two variants of the same mistake. The bootloader compares a SHA-256 of the image with a value stored next to it: an attacker who can write the image can write the hash. Or the bootloader verifies the signature of the image in flash and then loads the image from flash again, leaving a window to swap the content between check and use. We have seen both in update handlers more often than in boot code, but the boot code is where it hurts most.
Fix: verify an asymmetric signature with a public key that is itself protected (in ROM, in eFuses or by the previous stage), and verify the copy in RAM that you then execute.
7. Encryption mistaken for authentication
The flash is encrypted, so the team considers the firmware protected. But encryption without authentication does not prevent modification: an attacker who can flip bits in the ciphertext flips bits in the plaintext, and an attacker who glitches the loader skips the check that was never a check. On TriCore/AURIX controllers we have seen a related misunderstanding: the boot ROM checks the boot mode headers for consistency, not for authenticity, and authentic boot has to be implemented in the HSM. On one power-electronics ECU it had not been, and the application flash accepted any image with a valid checksum.
Fix: treat confidentiality and integrity as two requirements. Enable both flash encryption and signature verification, and use authenticated encryption for data that is stored outside the verified images.
8. Fault injection not considered
A single if (verify(image) == OK) is one instruction to skip. Voltage or clock glitching at the right moment flips that branch, and research on several widely used controllers has shown it works against ROM code. For a device that ships in large numbers, the attacker needs to succeed once and can then publish the method.
Fix: redundant checks with different code paths, randomised delays, checking the result against a non-trivial constant instead of zero, and where the chip offers it, hardware glitch detectors. For high-value products we include fault injection in the test to see how much effort an attack takes.
What we test
| Check | Method | Destructive |
|---|---|---|
| Fuse and option bytes state on production units | Read back through vendor tools or debug port | No |
| Debug and download modes | Probe JTAG, SWD, UART bootloader, USB DFU | No |
| Chain completeness | Modify each stage and partition, observe boot | No |
| Anti-rollback | Flash an older signed image | No |
| Key handling | Firmware analysis, update package analysis | No |
| Glitch resistance | Voltage or clock fault injection on the boot path | Possibly |
The result is a report with the exact fuse bits, boot stages and update paths that need to change, and a retest after the fix. Secure boot is also where the Cyber Resilience Act’s integrity requirement and EN 303 645 provision 5.7 become concrete, so the same report serves as evidence for both.
More about scope and prices on the hardware pentest page, or book a free 15-minute call.
FAQ
Frequently asked questions
Is secure boot required by law?
Not by name. The Cyber Resilience Act requires in Annex I Part I that products protect the integrity of software and configuration against unauthorised modification, and EN 303 645 provision 5.7 asks for verification of software integrity with a secure boot mechanism. Secure boot is the usual way to meet these requirements for firmware.
Does flash encryption replace secure boot?
No. Encryption stops an attacker from reading the firmware; it does not stop them from running modified firmware if they can get it onto the device or glitch the loader. Secure boot checks authenticity, encryption protects confidentiality. Most chips expect both to be enabled together.
Can you test secure boot without destroying the device?
Most of it, yes. Checking eFuses, debug ports, the chain and the update path is non-destructive. Fault injection and chip-off extraction may kill a unit, so we agree in advance which units may be sacrificed.