ESP32 Secure Boot and Flash Encryption: Protecting Firmware and Data on Deployed Devices
Our JTAG debugging guide covers getting deep visibility into a running ESP32 during development — but that same debug access, and the ease of re-flashing over USB or OTA, is exactly what you need to lock down once a device leaves your bench. If you're shipping an ESP32 project to other people, deploying it somewhere physically accessible to strangers, or just protecting the Wi-Fi credentials and API keys baked into your firmware, Secure Boot and Flash Encryption are the two features that actually matter. They're under-used in the hobbyist world because they're easy to get wrong in a way that permanently bricks the chip — so this guide is as much about the ways to avoid that as it is about turning the features on.
What Each Feature Actually Protects Against
FeatureProtects AgainstDoes Not Protect Against Secure BootRunning unsigned or modified firmware — the bootloader cryptographically verifies each stage before executing itSomeone reading data already in flash (that's Flash Encryption's job) or physical fault-injection attacks against well-funded, skilled attackers Flash EncryptionReading firmware, Wi-Fi credentials, keys, or other data directly off the external flash chip with a programmerSomeone with JTAG access and the enable keys, or a device where the encryption key itself was exposed during developmentUsed together, they close the two most common ways a hobbyist or small-batch product gets its firmware ripped, cloned, or tampered with: pulling the flash chip's contents directly, or swapping in modified firmware that phones home with your users' credentials.
Which ESP32 Variants Support This
All current ESP32 variants — the original ESP32, S2, S3, C3, and C6 covered in our variant comparison — support both Secure Boot and Flash Encryption, but the implementation differs by silicon generation. The original ESP32 uses Secure Boot V1 (RSA-based, older scheme) on early revisions and V2 (ECDSA/RSA depending on eFuse config) on later ones; the S2, S3, C3, and C6 use Secure Boot V2 exclusively, which is simpler to work with and what Espressif recommends for new designs. Check your specific module's chip revision before starting, since the workflow (menuconfig options, key formats) differs between V1 and V2.
Before You Touch a Single eFuse
This is the section to actually read, not skim. Both features work by burning eFuses — one-time-programmable bits in the chip's silicon. Once burned, they cannot be undone, on any ESP32 variant.
- Enabling Secure Boot without keeping your signing key safe means you can never sign new firmware for that device again. Lose the private key, and the device is stuck on whatever firmware was last flashed before you enabled the feature (or bricked, if something goes wrong mid-flash).
- Enabling Flash Encryption in "Release" mode disables the ability to read encryption keys back out or re-flash the plaintext bootloader. Development mode exists specifically so you can iterate without this risk — use it until your firmware and provisioning workflow are fully finished and tested.
- Test on a throwaway dev board first, not the unit you care about. A $5-10 module bricked while you learn the workflow is a rounding error; your finished project's only board is not.
- Back up your generated keys immediately, in more than one place. If you ever need to sign an OTA update or re-provision a device, that key is the only way to do it.
Enabling Secure Boot V2 (ESP-IDF)
- Generate a signing key: espsecure.py generate_signing_key --version 2 secure_boot_signing_key.pem — treat this file like a password, not a project asset to commit to a public repo.
- In idf.py menuconfig, under Security Features, enable "Enable hardware Secure Boot in bootloader" and select Secure Boot V2.
- Point the build at your signing key under the same menu, or sign the app image separately with espsecure.py sign_data if you're keeping the key off the build machine entirely (recommended for production).
- Flash with idf.py flash as normal for the first time — this is the flash that burns the Secure Boot eFuses and locks in your key's public digest.
- Verify with espefuse.py summary that SECURE_BOOT_EN reads as set, and that the device still boots correctly before you consider the process done.
Enabling Flash Encryption
- In idf.py menuconfig, enable "Enable flash encryption on boot" and choose Development mode initially — this lets the encryption key be read back for debugging, which Release mode disables.
- Flash normally. On first boot, the bootloader generates a device-unique encryption key internally, burns it into an eFuse block set to be unreadable by software, and encrypts the flash contents in place.
- Every flash after this point must go through esptool.py with encryption-aware handling, or use idf.py flash, which manages this automatically — a raw unencrypted image written directly will not boot.
- Once development and testing are complete, switch to Release mode for production units. This is the point of no return for that key: Release mode permanently disables JTAG (unless you separately keep it enabled, which weakens the whole scheme) and prevents reading the encryption key back out.
Secure Boot + Flash Encryption Together
For a real production deployment, you want both: Secure Boot ensures only your signed firmware runs, and Flash Encryption ensures nobody can read that firmware (or the credentials embedded in NVS) off the chip. Enable Flash Encryption first in Development mode, get Secure Boot working and verified, then move both to Release/production settings together as a final step — trying to debug two brand-new security features simultaneously in production mode is how boards get bricked.
OTA Updates With Secure Boot Enabled
Our FreeRTOS task guide and general OTA workflows still apply, with one addition: every OTA image must be signed with the same private key used for the initial Secure Boot setup before the device will accept it. Build your release pipeline around this from day one — an update mechanism that can't produce signed images is a dead end once Secure Boot is live.
Common Mistakes
MistakeConsequence Enabling Release mode Flash Encryption on a board you're still actively developing onLoses JTAG and key readback permanently on that specific board; requires full re-flash from scratch, and any data protected by the old key is unrecoverable Committing the signing key to a git repositoryDefeats Secure Boot entirely — anyone with the key can sign firmware your devices will trust Not testing OTA signing before deploying Secure Boot to units in the fieldField units become unable to receive updates, since unsigned or wrongly-signed images are rejected by design Assuming Flash Encryption alone stops firmware tamperingIt only stops reading flash contents — without Secure Boot, an attacker with physical/UART access can still write different code, unless the anti-rollback and encryption write-protection features are also configured correctlySafety and Practical Notes
These features exist for genuine reasons — protecting user credentials, preventing firmware cloning, and stopping malicious firmware from running on hardware you're responsible for — but they are also genuinely capable of permanently bricking hardware if enabled carelessly. Always develop and test the full workflow, including OTA, on a dev board you're willing to lose before touching a production unit. Keep signing keys backed up in at least two secure locations, and document your provisioning process before you scale past a handful of units, since re-deriving a lost process from memory after burning eFuses on fifty boards is not a good afternoon.
For a one-off home project, none of this is necessary — Secure Boot and Flash Encryption solve problems that matter when a device leaves your control: shipped products, devices in physically accessible locations, or anything handling credentials you don't want extracted with a $30 flash programmer. Know which category your project falls into before deciding whether the added complexity and irreversibility are worth it.
Related Guides
- Setting Up Marauder on the ESP32 Wi-Fi Dev Board for Flipper
- ESP32 as a WiFi Sniffer/Deauth Detector
- ESP32 OTA Updates: Wireless Firmware Flashing
- Debugging ESP32 Firmware with JTAG: OpenOCD, GDB, and ESP-IDF
- How to Program Addressable LED Strips: WS2812B Patterns, Effects, and Power Design
- I2C vs SPI vs UART: How to Choose and Use Serial Communication Protocols