Keep development and production keys in separate trust anchors, make the production build refuse development-signed images, and add an automated check to the release pipeline that fails if a test key, test certificate or default credential is present. Then verify one production unit by hand before every batch.
How it happens
A startup begins with one key because it is simple. Engineers flash with it for months. When production starts, the same key, or its public half in the bootloader, is already everywhere: in scripts, in a shared drive, in laptops. Nobody decides to ship a development key. It simply never gets replaced.
This matters because a signature proves that someone held the key, and nothing more. If the key is widely held, the proof is weak. The Update Framework describes the worst case as a properly signed but malicious file after an attacker compromises a signing key.
Separate the two worlds
| Item | Development | Production |
|---|---|---|
| Signing key | Shared, low value, rotatable | Offline or in a managed signer |
| Public key in bootloader | Dev public key | Production public key |
| Debug interfaces | Open | Closed |
| Credentials | Test accounts | Unique per device or none |
| Update server | Staging | Production |
A device built for production should not contain the development public key at all. If it does, anyone holding the development key can install their own image.
A release gate that catches it
- Search the built image for known development key fingerprints and fail if found. Keep a list of every fingerprint you have ever used for development.
- Fail the build if the image still contains debug flags, test endpoints or default passwords.
- Confirm the image is signed by the production key and not signed by any other.
- Compare the bootloader's embedded public key to the expected production fingerprint.
- Require a second reviewer to approve the gate result.
These checks are cheap to write and expensive to skip. Add the failures to a shared list so the same mistake cannot return.
Verify a real unit
Automation checks the build. A manual check on a real production unit confirms the line did what you meant. Take one unit from the first batch, try to boot a development-signed image, and confirm it is rejected. Try the debug port and confirm it is closed. Write the result down and keep it with the batch record.
What to do if you already shipped one
Do not wait. Work out which units carry the development trust anchor, whether they can accept an update that replaces it, and whether attackers could reach the update path. If devices can accept a signed update, plan a key replacement release. If they cannot, you may need a recall decision with your counsel. This is a good reason to design key replacement into the first version.
Quick check
Is a separate key really worth the effort for a prototype run?
For a handful of lab units, no. Once any unit reaches a customer, yes, because replacing a trusted key later can be very hard.
Can a scanner find a dev key inside firmware?
You can search the image for fingerprints you already know. Add that as a separate build check, since a generic dependency scan will not look for your own keys.
Sources
Last reviewed: 19 October 2026.