libsodium Gets First CVE After 13 Years: The Two-Line Fix

Want to learn ethical hacking? I built a complete course. Have a look!
Learn penetration testing, web exploitation, network security, and the hacker mindset:
→ Master ethical hacking hands-on
(The link supports me directly as your instructor!)
Hacking is not a hobby but a way of life!
The crypto library behind Discord, WordPress, and Zcash just got its first CVE. After 13 years. 😏 libsodium. You’ve probably never heard of it. But it’s everywhere.
libsodium is one of the most trusted cryptographic libraries in the world. Discord secures voice chat with it. WordPress validates updates with it. Zcash processes transactions with it. Stellar powers financial apps with it.
13,300+ GitHub stars. Bindings in every programming language you can think of. From PHP to Rust to Python to Go.
And it’s maintained by one person. Frank Denis. For free. In his spare time.
Yesterday he published CVE-2025-69277. 13 years. Zero CVEs. For a crypto library.
Here’s what went wrong:
libsodium has a function to check if an elliptic curve point is valid. It’s called crypto_core_ed25519_is_valid_point().
Edwards25519 (the curve behind Ed25519 signatures) has multiple subgroups. The main subgroup with ~2^252 points is where all safe crypto operations should happen. But there are also small subgroups of 2, 4, and 8 points.
The validation function was supposed to reject points outside the main subgroup.
The problem? The check was incomplete.
To verify that a point is in the main subgroup, you multiply it by L (the group order). If the result is the identity point (the mathematical equivalent of zero), then the point is in the main subgroup.
The identity point has coordinates where X = 0 and Y = Z.
The old code only checked X = 0. Forgot to check: Y = Z. Some invalid points slipped through.
The fix:
// OLD: return fe25519_iszero(pl.X);
// NEW: fe25519_sub(t, pl.Y, pl.Z); return fe25519_iszero(pl.X) & fe25519_iszero(t);
Two lines. That’s all.
Should you panic? No.
→ Only affects custom crypto protocols using this low-level function → Normal Ed25519 signatures are fine → High-level APIs not affected
Frank found his own bug while experimenting with Zig code. Saw weird results. Dug in. Found the missing check. Fixed it the same day. Patched all packages the same day.
One person built this. Maintained it for 13 years. For free. In his spare time. And he’s not alone. There are thousands of developers out there doing the same thing. Building tools we all depend on, no paycheck, and no recognition. Just doing the work.
To everyone out there maintaining a project like this, you deserve more credit than you’ll ever get. Thanks!