The RP2350’s debug-disable is meant to be permanent: an OTP flag, CRIT1.DEBUG_DISABLE, drives both cores’ debug access ports to zero and cannot be unset. Ledger Donjon’s hardware security team showed the flag is not the last word in the enforcement chain. The memory-mapped DEBUGEN register overrides it, and a laser can set DEBUGEN even after it has been locked.
Why the target was hard to hit:
- Debug-disable is triple-redundant in OTP and the lock bits are majority-voted across rows.
DEBUGENhas no redundancy, parity or vote documented in the datasheet. - Setting one register bit means hitting a few micrometres of silicon. A blind laser scan for it is impractical.
- So they localized it optically first. Toggle selected
DEBUGENbits in a loop, average 200 full-view frames per bit mask, subtract the two mean stacks to cancel sensor noise, thermal drift and unrelated switching. What survives is the emission that tracks the selected bits.
Then the fault itself:
- 980 nm pulsed laser at roughly 1.2 W, 100 ns pulses through a 50x objective, with the SWD port probed after every pulse for feedback.
- Two positions a few micrometres apart: one sets
PROC1(bus access through core 1’s access port), the other setsPROC1_SECURE. A pulse setting one bit could clear the other, so the script iterates between them until both hold. A 20x objective could not reproduce it — the wider spot hit both the set and clear regions at once. DEBUGEN_LOCKdid not stop the laser. Pulses setDEBUGENbits while the lock was already set, and set lock bits too, so firmware can never write the disabled value back.
Recovering the secret needed a second idea:
- The challenge firmware tightens the OTP page 48 runtime lock on every boot, which blocks even Secure-attributed debug reads. That runtime lock is discarded by an OTP reset.
- The recovery access port stays reachable with external debug disabled, so
CTRL.RESCUE_RESTARTtriggers a rescue reset: a full reset in which the boot ROM halts before any user firmware runs. - The page lock reverts to its permissive persistent value and no code re-tightens it. With both cores parked in boot ROM wait paths, they faulted
DEBUGENto0xc, halted core 1, and read the secret straight out of the OTP rows.
What the attack costs is the honest part: destructive backside decapsulation, around $250,000 of lab equipment, real hardware-security expertise, and physical possession of the chip. Secure boot still authenticates firmware; what falls is runtime confidentiality, since a Secure-attributed debug port can read and write memory, halt and single-step a core, and inspect registers. Encrypted boot still protects external flash from offline inspection.
Two lessons worth keeping. OTP redundancy protects the bits you store there, but a mutable register in the same path can undo them — persistent configuration and runtime control registers have to be evaluated together. And the software mitigations are best-effort by construction: ACCESSCTRL returns to all-open defaults after a rescue reset, before firmware can reconfigure it, and a periodic DEBUGEN check can be preempted by a debugger that halts the core first.
The conclusion generalizes past silicon: security analysis has to cover the whole enforcement path from persistent configuration through mutable control registers and reset behaviour, because every individual mechanism here did exactly what its documentation promised.