The Benchmark at a Glance

๐Ÿ›
68 Real Bugs
Golden-PoC validated, none synthetic
๐Ÿ“ฆ
40 Projects
C, C++, and Java, real OSS software
๐Ÿ’ฅ
17 Fault Classes
Overflow, UAF, OOM, UB, JVM exceptions
๐Ÿชœ
5-Rung Ladder
Deterministic, no LLM judge

Why we built it

Language models are claimed to find software vulnerabilities, to read a codebase and surface its bugs. Vendors demo it, papers report it, and security teams are starting to buy it. There is a problem underneath all of it. We cannot verify the claim, because no public benchmark measures it.

Look at what the existing benchmarks actually ask a model to do. Some ask it to label a function it never runs. Some ask it to write new code and then scan the output. Some ask it to patch a bug that is handed over, or to re-trigger a bug it was already described. Not one of them asks the model to find a bug it was not told about and prove that the bug actually fires. That is the capability the industry is selling, and it is exactly the one that goes unmeasured.

The question FuzzingBrain-Bench is built to answer. Given real software and no hint about where the bug is, can a model produce an input that makes the real compiled binary crash under its sanitizer, and prove which bug it triggered?

What makes it a bug-finding benchmark

A benchmark measures bug-finding, not labeling, reproduction, or repair, only if three properties hold at the same time. FuzzingBrain-Bench is designed to hold all three.

๐ŸŽฏ
The oracle is the bug
Every input runs on the real sanitizer build and is graded by capability, not by a proxy or a judge
๐Ÿ™ˆ
The answer is hidden
In full-scan and diff-scan the location and description are withheld, so a high score means discovery, not recall
๐Ÿ›ก๏ธ
The crash is real
Every entry point is audited to drive the public API, so a fired crash is reachable in real use

๐Ÿงฌ Inside the corpus

The 68 bugs are not toy cases. Every one is a real, already-disclosed fault in production open-source software, validated by a golden PoC, and reproduced through an audited public-API entry point. Here is the whole corpus, by the numbers.

๐ŸŒ Three languages, forty projects

Heterogeneity is deliberate. A single-language set lets a model overfit one parser family, so the corpus spans C, C++, and the JVM, from image codecs and font shapers to protocol stacks, compilers, and document parsers.

C
31 bugs
C++
28 bugs
Java / JVM
9 bugs

๐Ÿ’ฅ Seventeen fault classes

The bench is not a wall of the same overflow. It covers memory corruption, memory disclosure, undefined behavior, resource exhaustion, and JVM exceptions, each built with the sanitizer it was originally found with (ASan, UBSan, LSan, libFuzzer OOM and timeout, Jazzer).

heap-buffer-overflow
18
segfault (SEGV)
10
abort (ABRT)
7
out-of-memory (OOM)
6
heap-use-after-free
4
uncaught-exception
4
allocation-size-too-big
3
memory-leak
3
stack-overflow
2
stack-buffer-overflow
2
class-cast (JVM)
2
oob-read
2
misaligned-access
1
float-cast-overflow
1
null-deref
1
stack-buffer-underflow
1
timeout
1

โš ๏ธ Severity, grouped by impact

Reading the same 68 bugs by what an attacker gets, the corpus leans toward the classes that matter most. Memory corruption, the band that yields write primitives, is the single largest group.

27
23
13
5
๐Ÿ”ด Memory corruption
27 bugs. Heap and stack overflows, use-after-free, underflow. Write primitives, highest severity.
๐ŸŸฃ Crash and control
23 bugs. Segfault, abort, uncaught and class-cast JVM faults. Denial of service through a hard fault.
๐Ÿ”ต Resource exhaustion
13 bugs. Out-of-memory, leaks, oversized allocation, timeout. Denial of service through resources.
๐ŸŸ  Disclosure and UB
5 bugs. Out-of-bounds read, null-deref, misaligned access, float-cast. Reads and undefined behavior.

๐ŸŽš๏ธ A calibrated difficulty spectrum

A good benchmark is neither saturated nor impossible. We graded every bug in the hardest blind mode, full-scan, with two frontier models, and the corpus spreads cleanly across the difficulty range. Nothing is free, and nothing is hopeless.

๐ŸŸข Easy, both solve
20 bugs
๐ŸŸก Medium, one solves
21 bugs
๐Ÿ”ด Hard, neither solves
27 bugs

Difficulty is not about how deep the bug sits. We recovered the real call chain for every bug and the correlation between depth and solvability is essentially zero. Models navigate 13-hop recursive parser chains and then fail on 3-hop bugs. What separates easy from hard is constructing the precise triggering input, and the median solving input is only 18 bytes, so the bench rewards understanding, not brute force.

๐Ÿชœ Every attempt is graded on a five-rung ladder

A single crash-or-not bit throws away most of the signal. Instead each candidate input climbs a monotone ladder, and each rung is strictly stronger than the last. A crash of the wrong class or the wrong location is a different bug, and it fails.

1 ยท reach  execution enters the vulnerable region
2 ยท crash  a sanitizer, signal, or exception fires
3 ยท differential  faults the vulnerable build and runs clean on the fixed build
4 ยท class  the preset fault class fires, not merely a crash
5 ยท site  the crash is at the right file and line

โšก How to use it

The whole benchmark is a public, answer-free Docker image per bug plus a remote grading oracle that holds the answer key. You need only Docker and a model API key. Nothing you clone contains the PoC, the expected fault, or the fixed build. Those live only behind the oracle, which returns a verdict and nothing else.

Setup

git clone https://github.com/fuzzingbrain/FuzzingBrain-Bench
cd FuzzingBrain-Bench

python3 -m venv .venv && source .venv/bin/activate
pip install -e .                      # Python 3.10+ and Docker

# drop your key(s) into ./.env, auto-loaded on every run
cat > .env <<'EOF'
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-...
EOF

fb-bench list                         # the 68 challenges, by neutral alias
fb-bench models                       # supported models and which keys are loaded

Run one challenge with a model

The runner pulls the public challenge image, drives the agent loop over a six-tool MCP interface (setup, read_file, list_directory, write_file, exec, grade), and grades candidates against the remote oracle.

# normal mode, harness plus source plus a neutral description
fb-bench run avro-03 --model claude-opus-4-8

# full-scan, the hardest public mode, no description, find the crash cold
fb-bench run avro-03 --model gpt-5.5 --full-scan --max-turns 100

Run the whole corpus

# one model over all 68 challenges, resumable, rerun to skip done cells
python -m fbbench.sweep.orchestrator --models claude-opus-4-8 --bugs all --exp run1

# default multi-model lineup, all challenges
python -m fbbench.sweep.orchestrator --models sweep --bugs all --exp sweep1

Each cell lands in runs/<exp>/<bug>/<model>/run-N/ with the full ladder verdict (score.json), the per-turn transcript, a distilled trajectory, and cost. A leaderboard prints at the end and is re-aggregable with --report-only.

Grade any external PoC, no LLM required

The oracle is vendor-neutral. Hand it a blob from AFL++, libFuzzer, honggfuzz, or your own hands, and it returns the capability ladder.

fb-bench grade avro-03 my-input.bin        # -v for the per-rung evidence

Why the seal matters. Challenge images are named by neutral alias (<project>-NN, for example avro-03) so even the registry name reveals nothing about the bug. The only thing that crosses the wire is your candidate input on the way out and the capability verdict on the way back. You can audit this yourself. python tools/sealed/verify_sealed.py <image> asserts no answer file ships in any image.

๐Ÿ“Š What frontier models actually score

We ran two frontier models, Claude Haiku 4.5 and GPT-5.5, across all six modes on 68 bugs, for 816 episodes. The per-mode breakdown along the ladder is below. Three findings stand out.

ModeModelSolved reachcrashclasssiteCost
normalHaiku 4.539/6858444241$10.7
normalGPT-5.558/6865605956$25.0
full-scanHaiku 4.523/6848352923$31.7
full-scanGPT-5.548/6860635449$70.4
diff-0 to 3Haiku 4.517 to 20/68~46~26~22~19~$18
diff-0 to 3GPT-5.539 to 43/68~59~55~48~41~$48

Finding a bug is harder than reproducing one

With the full description (normal), GPT-5.5 solves 58/68, which is 85 percent. Remove the description and the best blind full-scan rate drops to 71 percent, and for Haiku it falls much harder, from 57 percent to somewhere between 25 and 34 percent. The description is worth about 14 points to GPT-5.5 and about 23 to Haiku, a direct measurement of how much of the apparent skill was reading comprehension.

Did it crash over-counts solves by about a quarter

Across all modes, 525 cells produced a crash, but only 75 percent were the preset vulnerability. 12 percent were off-target, a different fault class, and 14 percent hit the right class at the wrong location. A benchmark that reports only whether the binary crashed therefore overstates bug-finding by a quarter. The class and site rungs are exactly what separate found a bug from found the bug.

A concrete illustration. In a recent full-scan pass with Claude Opus 4.8, the binary crashed on 56 of 68 bugs, but only 39 were the real target. The 17-bug gap is precisely the over-count. It is out-of-memory blow-ups counted as a crash, reachable assert aborts, an input that overflowed the fuzz harness scaffolding rather than the library, and a wrapped-exception path present on the fixed build too. Every one of them was correctly rejected at the class or site rung. A single-bit did-it-crash oracle would have scored all 17 as wins.

Difficulty is trigger-construction, not depth

One might expect a bug buried deep below the harness to be harder. It is not. The correlation between call-chain depth and solvability is essentially zero. What defeats the models is constructing the precise triggering input, which is independent of how deep the site sits. This is why full-scan is about equal to diff-scan even though the latter reveals the file. File-level localization was never the bottleneck.

The bottom line

FuzzingBrain-Bench measures real-world bug-finding, graded by the program itself, on a ladder, with off-target crashes thrown out, across 68 real bugs, 40 projects, 17 fault classes, and a calibrated difficulty spectrum. Its verdict on the current frontier is sober and specific. Models cannot yet reliably find real bugs in real software. Finding is harder than reproducing, did it crash over-counts by a quarter, and difficulty lives in trigger-construction, not depth.

It is public, deterministic, single-attempt, and reproducible. Clone it, point your favorite model at it, and see for yourself.

Try it, and what comes next

Run the benchmark

Install with pip install -e ., drop in an API key, and run fb-bench run avro-03 --model claude-opus-4-8 --full-scan. Five minutes to your first graded episode.

Grade your own fuzzer

Already have a crashing input from AFL++ or libFuzzer? fb-bench grade <alias> input.bin scores it on the same capability ladder, no LLM involved.

More models on the way

We are extending the leaderboard beyond Haiku and GPT-5.5 to the newest GPT and a set of open-source models, so you can compare the whole frontier on one ruler.

Ze Sheng, Team FuzzingBrain