MuPDF's PDF encryption key had only 512 possibilities, and a script cracks it in 11 ms

A random-number generator seeded once with the clock and read from the wrong bits left a 128-bit AES key with nine bits of real entropy.

In brief

MuPDF before 1.28.5 seeded a drand48-style generator with the current Unix time and read bytes from bits that ignore most of the seed, so timestamps 512 seconds apart give identical keys. The author brute-forces all 512 in about 11 ms of unoptimised Python.

Foxit Reader has a related flaw; already-published PDFs cannot be protected retroactively.

How a timestamp collapsed into nine bits

Post cover
Post cover

The write-up shows that MuPDF seeds a 48-bit LCG once, with the Unix time in seconds, and takes each key byte from bits 17 to 24 of the state. Because multiplication and addition only carry bits upward, higher bits never touch those outputs, and the low 16 bits are a fixed constant, so only 9 timestamp bits matter. That leaves 512 possible file keys. Fixed in MuPDF 1.28.5.

Foxit PDF Reader 2026.1.3.36551 derives the key as SHA-256 over the timestamp, 32 effectively zero bytes and a constant. OpenPDF 3.0.5 and iText 9.7.1 seed an ARC4 stream with the millisecond clock and JVM free memory, a weaker problem the author calls higher-variance.

The thread: it's not the bit count

"…the number of bits in the key space isn't the real story; the keys simply aren't cryptographically random." — tptacek

Documents already encrypted by a vulnerable version stay exposed. Anything sensitive sent that way should be treated as readable.

Get breakdowns like this every day

The top Hacker News stories, unpacked — by email, Telegram, or RSS.

Next story · 8 of 8 Read more
🚀Tech

Alpine upgraded GitLab and stayed vulnerable, because the fix lived in a Ruby patch

The CVSS 10.0 flaw sat in Ruby's regex engine, and GitLab applies its fix only in its own packages. Alpine's image used standard Ruby.

★ 78 · 💬 27 · alpinelinux.org · 1 min