When LLMs Compress Exploit Development
CVE-2025-9951, the EPSS paradox, and why time-to-exploit is now the binding constraint on vulnerability impact
The vulnerability
CVE-2025-9951 is a heap-buffer-overflow in FFmpeg's JPEG 2000 decoder (affects versions before 8.0). The decoder validates the SIZ marker (which describes component dimensions) and the CDEF box (which assigns components to output channels) separately, but never checks them against each other. So you can craft a file that maps a full-resolution component into a smaller subsampled plane. When the decoder writes that component, it walks the larger source geometry and overwrites the smaller destination, giving a controlled heap overwrite of the classic kind.
The repo at fm0ss/cve-2025-9951-ffmpeg-jp2-poc has two milestones. The first gets autonomous callback execution running under GDB with a predictable heap layout. The second (August 2025) is more interesting: it leaks PIE, heap, and libc addresses straight from the decoder's error messages, chains those leaks into setcontext execution, and does it all with ASLR enabled and no debugger. The published version exits at _exit(90). A follow-up experiment went further and executed shellcode.
The EPSS anomaly
CVE-2025-9951 has an EPSS score of 0.0040 (0.33rd percentile). EPSS predicts the probability of a vulnerability being exploited in the wild within 30 days, so a score at that level amounts to a prediction that exploitation will not happen, and by the time the score was published it already had.
The probability EPSS assigns to this vulnerability being exploited in the wild within thirty days.
Won't be exploited. High attack complexity, no public exploit, no observed activity.
Full RCE in one week of part-time work, with ASLR on and no debugger needed.
EPSS was trained on pre-2023 data, when sophisticated exploits took 6+ months to develop. High complexity now means little more than a requirement for codec knowledge, and the model has not been recalibrated to account for that.
EPSS learned from historical patterns. It saw that certain kinds of bugs got weaponized fast: bugs found in the wild, bugs with existing exploit frameworks, bugs in widely-used software. It weighted those signals heavily. But all that training data came from an era when building a real exploit meant months of grinding through manual reverse engineering, heap grooming, ROP chains. The barrier was genuinely high, and it no longer is.
Before LLMs: exploit development as a scarce skill
Pre-2023, building an exploitation chain for an ASLR-protected, position-independent binary required:
- Reading assembly: Understand calling conventions, spot gadgets, map what objdump shows to what actually runs.
- Heap internals: glibc layout, tcache, chunk coalescing, spotting when something's poisoned. And this stuff changed with every glibc version.
- Codec knowledge: For a JPEG 2000 bug, you need to understand sampling factors, transforms, wavelets, entropy coding. This isn't something you pick up casually; it's specialized.
- Exploit engineering: Leak primitives, relative pointers, finding gadgets that actually run on your path, chaining them into RCE.
These skills did not transfer between themselves, and learning one of them was no substitute for the others. The work needed someone with years spent on low-level systems, ideally with shipped exploits already behind them, and that combination was rare enough to be found only in advanced red-teamers, selected government researchers, and a handful of independent researchers with a decade or more of work behind them.
Producing a 512-byte JPEG 2000 file that triggered code execution would have taken 4 to 8 months of focused work in 2020, which is simply how long sophisticated heap exploits took against commodity libraries at the time. The work looked like:
- Build a test harness and reproduce the bug deterministically.
- Measure the exact write pattern through hardware watchpoints and heap dumps.
- Static-analyze the binary for reachable targets and gadgets.
- Construct a payload byte-by-byte, often going through dozens of failed iterations.
- Groom the heap through careful sequence of allocations.
- Leak addresses, a step that often required its own sub-exploit or a side channel.
- Port the result to fresh binaries or ASLR variants, discovering what broke each time.
This created a filter: bugs only got exploited if they were valuable enough to justify months of expert time. What counted as valuable enough was never fixed, since it depended on who was attacking and on what else was available to them. Because of that 4-month barrier, whole categories of bugs stayed untouched: weird memory corruption in codecs, race conditions in thread pools, off-by-one checks. Even if they were perfect targets, they weren't worth spending that much time on. The scarcity of people who could do this work was, ironically, a defense.
The LLM acceleration
The CVE-2025-9951 repository shows what has changed. The writeup opens not with a finished exploitation chain but with a hypothesis, and proceeds through a series of increasingly specific investigations into whether the validation would pass, what the write actually looked like, which objects were in reach, and what survived cleanup.
And at each step, LLMs could help in ways that matter:
- Reverse engineering: Asking what a routine does and getting a usable answer, instead of working through the disassembly by hand. Questions about glibc behaviour could be resolved without digging through documentation.
- Payload construction: The challenge was reversing through a JPEG 2000 codestream to encode the exact heap state you want. An LLM can draft the codec logic, spot off-by-one bugs and walk through the pipeline, which removes the need to implement that layer by hand.
- Problem spotting: The researcher hit a weird issue where changing pixels changed the heap structures being encoded. An LLM could name that as a fixed-point problem and suggest iteration. That kind of insight could take days solo.
- Code generation: Six passes of Python for payload generation, geometry scanning and profiling, drafted by an LLM and then iterated on, where in 2020 the same work would have been written entirely by hand.
The EPSS model was trained on data in which sophisticated memory corruption in a media codec sat in the long tail of exploitation risk. The model learned that such bugs require months and specialized expertise. But that assumption no longer holds when that expertise can be partially automated. The barrier has shifted from months of a rare human to weeks of an ordinary engineer with LLM assistance.
What changed: the timeline
The CVE-2025-9951 research required:
- Validation investigation (days)
- Write-pattern measurement (days)
- Target identification and scanning (1–2 weeks)
- Heap state reconstruction and payload iteration (2–3 weeks)
- ASLR variant and disclosure chain (3–4 weeks)
One week of focused effort, and not full-time effort at that, was enough to weaponize an ASLR-defeating exploit with real RCE.
In 2020, with manual heap dumping, GDB scripting, and no LLM-assisted code synthesis, that same work would have consumed 4–6 months of a full-time specialist's time. This is not just a productivity gain. It is permission to do the work at all. A researcher who in 2020 would have shelved the bug as too specialized to be worth half a year of work can now develop it as a side project.
The same reasoning scales. There are hundreds of memory-corruption bugs in codec libraries, network parsers, and file format handlers. Most are never exploited not because exploitation is impossible, but because it was too expensive. LLMs have lowered that expense.
Why EPSS is now miscalibrated
The EPSS model weights certain features: whether a public PoC exists, whether the bug sits in a widely-deployed component, and what attack complexity is required. It learned those weights from data in which high attack complexity meant months of specialized work.
That definition has shifted. A bug marked high attack complexity in CVSS 4.0 now indicates only that it lacks a trivial linear overflow, or that it requires heap grooming. It no longer indicates six months of expert work. The exploit-development barrier has compressed, and EPSS has not recalibrated to reflect that.
CVE-2025-9951 scored 0.0040 partly because it carries CVSS 4.0 metrics of AC:H (attack complexity: high) and AT:N (attack requirements: none). The model reads this as low-probability exploitation. In JPEG 2000 exploitation, however, high attack complexity now means understanding component sampling and wavelet transforms, rather than inventing a new ROP gadget discovery technique.
The EPSS score reflects pre-LLM calibration, and the actual risk is correspondingly higher than it records.
Time-to-exploit as the new constraint
Before LLMs, time-to-exploit varied wildly:
- Trivial bugs (use-after-free in a main loop): 1–2 weeks
- Moderate bugs (off-by-one in copying code): 2–4 weeks
- Complex bugs (subtle memory corruption in a codec): 4–8 months
- Architectural bugs (race conditions in thread pool): 2–3 months
The variance meant that which bugs got weaponized depended heavily on opportunity. If a researcher with the right skills happened to be looking at FFmpeg and found a JPEG 2000 bug, and if they had funding or motivation to spend 6 months on it, it could be exploited. Failing that, it sat untouched.
LLMs have compressed the time across the board. More importantly, they have made that time more predictable and less dependent on rare expertise. An engineer with 2–3 years of systems experience can now tackle what previously required someone with 10+ years and a reputation for exploit shipping.
CVE-2025-9951 demonstrates the magnitude of this compression: one week of focused effort to produce a weaponized, ASLR-defeating exploit with real code execution. In 2020, that same work would have consumed 4–6 months of a specialist's time. Now a researcher with AI assistance and 2–3 years' experience can do it in days.
The binding constraint is no longer expertise but total time from vulnerability disclosure to active exploitation, and that time is now measured in days rather than months or years.
Implications for vulnerability management
The standard model of vulnerability management assumes a timeline:
- Vulnerability disclosed (day 0)
- Patch released (days 0–30)
- Exploit development begins (day 30–90)
- Weaponized exploit ships (day 90–180)
- Mass exploitation (day 180+)
This timeline assumed step 3 takes 60–120 days for sophisticated vulnerabilities. LLMs have collapsed step 3 to 20–30 days. The window between the patch becoming available and attackers holding working code has shrunk from months to weeks.
Patches themselves have not become faster to deploy. Enterprise patching still takes 30–90 days on average. The gap between when code execution is possible and when defenses are in place has narrowed dramatically. In effect, every memory-safety vulnerability is now on a compressed timeline. There is no longer a six-month window in which the difficulty of exploitation provides a buffer.
What this means for Cofibrant
This is the core problem Cofibrant solves. Traditional vulnerability patching assumes that exploit development is hard and slow, and patches are shipped 30–90 days after disclosure on that assumption. The timeline worked while sophisticated bugs took months to exploit, and it fails once time-to-exploit is measured in days.
Cofibrant's approach, provable RCE-immunity at the compiler level with zero code changes, targets exactly this compressed timeline. If a memory-corruption vulnerability is impossible by construction (not by obscurity, not by defense-in-depth, but by formal guarantee), then the disclosure-to-weaponization timeline becomes irrelevant. The vulnerability exists in the source, but it cannot execute.
The CVE-2025-9951 research proves that LLMs have made exploit development accessible to a much broader population. That accessibility is good for transparency in security research. It is also a forcing function for defense. The old assumption that memory safety is desirable but optional because exploitation is hard is no longer viable when sophisticated attacks compress to weeks.
Conversely, the presence of LLM-assisted exploitation does not mean memory safety is required in all code. It means the cost-benefit calculation has shifted. For code exposed to untrusted input, for code in high-value targets, for code that handles sensitive data, the risk is no longer that low-probability memory corruption might someday be exploited by a specialist. It is that an engineer with an LLM can exploit memory corruption in days, given the decision to try.
Conclusion
CVE-2025-9951's EPSS score of 0.0040 reflects historical data about vulnerability exploitation. The actual risk is higher because the premise has changed. Time-to-exploit is no longer a months-long research effort for sophisticated bugs. It is now measured in days, at one week of focused engineering effort with LLM assistance, and it is within reach of researchers who a decade ago would have dismissed such work as impossibly specialized.
The vulnerability itself is a good example of how that compression happens: a subtle validation gap, a codec-specific understanding requirement, a heap layout problem, a disclosure chain. Each of these is individually tractable and none requires breakthrough insight. What changed is that an engineer can now work through them systematically with an LLM providing real-time research support, code synthesis, and problem decomposition.
This is not a failure of EPSS or a weakness in CVSS metrics. It is a fundamental shift in the economics of vulnerability exploitation. The barrier to weaponization has moved from requiring a rare human with specialized expertise to requiring only time and determination. In a world where LLMs can compress specialized expertise into available tools, that shift has security implications that are just beginning to play out.