The finding
ML-KEM requires constant-time decapsulation because the reject-vs-accept distinction must not be observable. We have found implementations whose decapsulation branched in a timing-distinguishable way — the KyberSlash class targets exactly this. Verify constant-time at the binary level.
ML-KEM tolerates implicit rejection by design: on an invalid ciphertext it returns a deterministic pseudo-random shared secret rather than an error. That property is only safe if the path that produces it is indistinguishable, by timing, from the accepting path.
Constant-time, undone by the compiler
A subtler version of the same class: source code that is written to be constant-time but is compiled into branchy code by the optimiser. The property the developer reasoned about at the source level no longer holds in the binary the machine actually runs.
Verify at the binary level
Check the constant-time property where it matters — at the binary level, with tools like ctgrind, TIMECOP, or dudect — not at the source level. The KyberSlash class of timing attacks specifically exploits the gap between source-level intent and compiled reality.
Weak randomness in keygen
A related and surprisingly common bug: keygen drawing randomness from a non-cryptographic source, or one that has not been seeded. Post-quantum primitives have specific entropy requirements — a working implementation does not prove the RNG path is sound.
Have a system that needs this?
Secure my organization