Black Hat Asia 2026 (Singapore, Apr 23–24) — Briefings Deep Dives

Breaking the Illusion of Key Zeroization: How OS, Libraries, and Hardware Keep Your AES Keys Alive

Talk 06 · Cryptography & systems security · analysis from the speakers' published deck

Sep 23, 2026 · conferences · 10 min read · 1900 words advanced

Breaking the illusion of key zeroization — your AES keys don't disappear.

conferences blackhat cryptography memory-forensics systems

Official recording, Black Hat YouTube channel · open on YouTube ↗

Toyofumi Sawa and Professor Kuniyasu Suzaki (IISEC) attack a comfortable assumption: that once your software is done with a cryptographic key, the key is gone. "Zeroization", overwriting keys in memory after use, is required for defense-in-depth, forward secrecy, and certifications like FIPS 140-3. Using an FPGA that continuously scans physical DRAM (so it sees memory the OS can't hide), they show the assumption is often false. AES keys from OpenSSH, OpenSSL, Firefox, Chromium, Edge, and 7-Zip survive abnormal process termination (SIGKILL, SIGABRT), get silently duplicated into kernel memory by vector-register context switches and by crash-reporting core dumps, and on many systems persist across a reboot. Normal exit usually clears the key; almost nothing else does. The uncomfortable conclusion: zeroization is a whole-stack property, spanning application, library, OS, and hardware, and it cannot be verified from user space at all.

Post 06 of my Black Hat Asia 2026 series. Analysis-first: the research method, the findings, and the layered fixes. This is defensive systems research; there are no attack recipes to omit.

1. Why zeroization matters, and the illusion around it

The talk sets up with the familiar "encrypt everything" story: data at rest (BitLocker, FileVault, LUKS), data in transit (TLS, SSH, Signal), and increasingly data in use (confidential computing, SGX, SEV). All of it depends on keys, and a key that lingers in memory after use quietly undoes the encryption it was protecting. The team frames zeroization as required from three angles:

PerspectiveWhy residual keys hurt
Defense in depthResidual keys expand the attack surface; reliable zeroization reduces the chance a compromise turns into a decryption
Forward secrecyIf a key's lifetime is unknown, a later system compromise can expose past communications
CertificationStandards (FIPS 140-3) require zeroization of Sensitive Security Parameters

Their pointed example: "Ransomware without zeroization is not a threat." If the ransomware encrypts your files but leaves the key in memory, you recover the key and the files. Zeroization is what makes the encryption stick, for attacker and defender alike.

The "illusion" is the set of things engineers assume handle zeroization automatically: free() clears memory, process exit removes secrets, reboot erases everything, "the OS takes care of it." The talk's thesis is that every one of those beliefs is unreliable, and you can only tell by looking at physical memory from outside the OS.

2. The method: watching DRAM from an FPGA

The measurement approach is what makes the results trustworthy. Zeroization cannot be examined from user space, because the OS holds copies of a process's state (in kernel buffers, saved register contexts, page caches) that user code can't inspect. So the team observes memory from below the OS:

  • An SoC FPGA (a Xilinx KR260) with a custom core, Periodic-AESKeyFinder, continuously scans physical DRAM over the memory bus, roughly one full pass of 8 GB every ~2 seconds.
  • It reuses the well-known AESKeyFinder forensic technique (famous from the cold-boot-attack research), which locates AES keys by recognizing the structure of an expanded AES key schedule in memory. The team's tweak is partial key-schedule matching, so it can spot keys even when only part of the schedule is present.
  • They also test PCIe and Thunderbolt DMA setups against Intel desktops and laptops, so the results span architectures (x86-64 and AArch64) and platforms.

Because the scanner lives on hardware with direct memory access, it sees keys "beyond OS control", exactly the copies the illusion assumes don't exist.

3. Four questions, four uncomfortable answers

RQQuestionFinding
RQ1On normal process termination, are user-space keys zeroized?Usually yes (the ✓ column) — the one case that mostly works
RQ2On abnormal termination (SIGKILL, SIGABRT, SIGTERM, core), are they zeroized?Almost never — keys remain
RQ3Are keys duplicated into memory the process can't read/write?Yes — via context switches and core dumps
RQ4Do residual keys persist after a reboot?Often yes, depending on OS/platform

3.1 Abnormal termination leaves keys behind (RQ1/RQ2)

Across a matrix of applications, libraries, OSes, and architectures, the pattern is stark. On normal exit, keys are cleared for almost everything tested (OpenSSH/OpenSSL, Firefox/NSS, Chromium/BoringSSL, Edge/Schannel). On SIGKILL and other forced terminations, keys are left in user space in essentially every case. The reason is simple and general: normal exit runs the library's cleanup paths (destructors, atexit handlers, explicit wipes), while a forced kill runs none of them, the process just stops, and whatever was in its memory stays there until those physical pages are reused. A telling detail: 7-Zip left keys in memory even on normal exit, so "clean shutdown clears keys" isn't even universally true.

Why this is the practically important finding. Attackers and crash conditions don't send SIGTERM and wait politely. A process that is OOM-killed, force-quit, or crashed is exactly the state an incident responder or an attacker finds it in, and that is precisely the state where zeroization fails. The one case that works (graceful exit) is the one an adversary won't give you.

3.2 Keys duplicate into places the process can't touch (RQ3)

This is the most subtle result, and the one with the clearest "not the app's fault" character. Even a perfectly-behaved application that wipes its own key buffer can have the key copied elsewhere by the system:

  • Vector-register context switches. AES implementations keep round keys in the CPU's wide vector registers (AES-NI / NEON). When the OS preempts the thread, it saves those registers into kernel memory and loads the next thread's. The team directly observed keys duplicated into kernel space this way. The application never asked for that copy, can't see it, and can't wipe it, it lives in the kernel's saved-context area.
  • Core dumps. When a process crashes, crash-reporting tools duplicate its memory, including keys, into a dump file, which may then be transmitted externally (the "crash report leakage" scenario).
Key duplication via vector-register context switch Running thread round keys in vregs Kernel (on interrupt) saves vregs → kernel mem = a copy of the key Next thread its vregs loaded the app wiped its own buffer — but the kernel's saved copy remains, unreachable from user space

Fig. 1 — The application can zeroize its own memory and still leak the key, because the OS copied it out of the registers during a context switch.

3.3 Some keys survive a reboot (RQ4)

The last result breaks the "reboot erases everything" belief. Whether keys survive depends heavily on OS build and platform:

EnvironmentWarm bootAfter kernel crashReset switch
Linux (Xilinx Zynq SoC)✘✘✘
Linux 5.15 FIPS (Intel)✓✓✓
Linux 6.8 generic (Intel)✘✓✓
Linux 6.8 generic (AMD)✓✓✓
Windows 11 FIPS (Intel)✘✓✓
Windows 11 (Intel)✘✓✓

(✓ = keys cleared / not found after the event; ✘ = keys still present.) The takeaways the team draws:

  • FIPS-compliant Linux zeroizes on reboot, generic builds often don't, on a warm boot the memory controller may not clear DRAM, so the previous contents survive into the next boot.
  • PCs generally do clear memory after a kernel crash or a hardware reset, but a plain warm reboot is the weak case.
  • The SoC keeps keys even after a reset, embedded platforms are the worst offenders, which matters for the growing pile of ARM-based edge and IoT devices doing crypto.

4. Whose job is it? Every layer's

The paper's organizing insight is that key lifetime is an emergent property of interactions across layers, so no single owner can guarantee it. The failures map cleanly onto the stack:

LayerFailure mode
ApplicationMissing signal handlers (no wipe on abnormal exit); core dumps include key pages
Crypto libraryRound keys left in registers / temporary buffers after operations
Operating systemLazy page zeroization; key duplication via saved register contexts; no wipe on SIGKILL
Hardware / platformNo memory zeroization on warm reboot (esp. SoCs)

Because the copy that leaks (the kernel's saved vector-register context) is created by a layer below the one that owns the key (the application), a perfectly-written app cannot close it. That is the core argument for why this must be tackled as a system, not patched app by app.

5. Recommendations, by role

Application developers: implement signal-handler zeroization so keys are wiped on abnormal termination too, and exclude sensitive pages from core dumps (e.g. madvise(MADV_DONTDUMP) on the key region).

Library developers: zeroize temporary key material left in registers and scratch buffers immediately after each cryptographic operation, not just the long-lived key object.

OS developers: zeroize the kernel memory that stores saved register contexts when a process exits, and implement zeroization for SIGKILL (the case nothing currently handles).

System managers: disable core dumps for services holding keys, and configure crash-reporting tools not to transmit dumps externally.

Hardware/platform vendors: document memory-zeroization behavior on reboot clearly, so integrators know whether a warm boot clears DRAM.

Certification testers: understand these cross-layer issues and require vendors to document how their platforms actually behave, rather than assuming a library-level wipe is sufficient.

Doesn't calling a secure-wipe function (memset_s, OPENSSL_cleanse) solve this?

It solves the application-buffer case on the paths where it runs. It does nothing for (a) abnormal termination that never reaches the wipe, (b) copies the OS made in saved register contexts, or (c) core dumps taken before the wipe. Those are exactly the cases the FPGA caught. The wipe is necessary but not sufficient.

Is confidential computing (SGX/SEV) affected?

The talk frames "data in use" encryption as the motivation, and the same discipline applies: even inside an enclave, keys can be duplicated by the mechanisms studied unless the platform guarantees otherwise. The general lesson, verify zeroization by observing memory, not by trusting the API, holds regardless of the confidential-computing marketing.

Why does a warm reboot leave keys but a hardware reset clears them?

On a warm reboot the DRAM is often not re-initialized by the memory controller, so its contents survive into the next boot. A hardware reset or power cycle is more likely to trigger memory training/clearing. This is platform-dependent, which is exactly why the team asks vendors to document it.

How would I check my own system?

You need out-of-band memory access (DMA over PCIe/Thunderbolt, or an FPGA on the bus) plus an AES-key-schedule scanner. The team's Periodic-AESKeyFinder is open source. From inside the OS you fundamentally cannot see the kernel-side copies, which is the whole point.

Takeaways

  • Zeroization mostly works on graceful exit and mostly fails everywhere else, abnormal termination leaves keys in user space almost universally.
  • Keys duplicate into kernel memory via vector-register context switches and into core dumps, places the owning application cannot wipe.
  • Keys can survive a warm reboot, especially on non-FIPS builds and embedded SoCs; hardware reset and kernel crash more reliably clear DRAM.
  • It's a whole-stack property. A perfect application can't fix a copy the kernel made. App, library, OS, and hardware each own part of the fix.
  • You can only verify it by observing physical memory from below the OS, an FPGA/DMA scanner, not a user-space check.
  • Concrete fixes exist per layer: signal-handler wipes, no-dump key pages, register/scratch wiping, kernel context zeroization, SIGKILL handling, and documented reboot behavior.

References & further reading

← prev: DFIR Agent Injection next: Auth Reflection Bypass →
© cvam — written in plaintext, served warm