← Back to blog

The OpenSSF CVE Benchmark and AI Code Review: What It Proves, and How to Run Your Own

The only reproducible security benchmark vendors cite was built for SAST, in one language, from CVEs every model has read. The method still transfers; the number does not.

8 min read
The OpenSSF CVE Benchmark and AI Code Review: What It Proves, and How to Run Your Own

Every vendor of an AI code reviewer says it finds security bugs. Ask for evidence and you get one of three things: a demo on a toy repository, a percentage from an internal test set nobody outside the company can inspect, or a reference to the OpenSSF CVE Benchmark. The third is the only one that is reproducible, which makes it worth understanding properly — including what it does not measure, which is most of what an AI reviewer does.

This post explains what the benchmark contains, how it scores a tool, why it is a 2020-era JavaScript corpus and what that implies for evaluating a 2026 LLM reviewer, and then the practical part: how to run the same methodology, replaying real vulnerabilities and their fixes, against whatever reviewer you are considering, on your own code.

What the OpenSSF CVE Benchmark is

The benchmark was built by the Open Source Security Foundation’s Security Tooling working group, with contributors from Google, GitHub, Mozilla, Tencent and OWASP among others, and was announced at Black Hat Europe in December 2020. It is MIT-licensed and lives on GitHub as ossf-cve-benchmark.

Its idea is simple and, at the time, unusual. Instead of testing security tools against synthetic snippets written to contain a bug, it collects a little over two hundred real, validated vulnerabilities — 218 at launch — from published CVEs in open source JavaScript and TypeScript projects. For each one it records two states of the real codebase: the commit that contained the vulnerability, and the commit that fixed it.

That pairing is what makes it a benchmark rather than a dataset. A tool is run against both states and scored on two questions:

  • Detection. Did the tool flag the vulnerability in the pre-patch code, at the right location?
  • False positives. Did the tool still flag it in the post-patch code, where the vulnerability no longer exists?

A tool that reports everything scores perfectly on the first and terribly on the second. A tool that reports nothing does the reverse. The benchmark forces the trade-off into the open, which is the same precision-recall tension we described in the post on false positives.

Mechanically, the repository ships drivers for ESLint, CodeQL and NodeJsScan, configured through a config.json and run from a small CLI (bin/cli run --tool eslint-default is the canonical example). The maintainers noted that a new tool integration typically needs fewer than 200 lines of code, and the stated roadmap was to add more languages and more tools.

What it is good at measuring

Known vulnerability classes in a single language, with ground truth. Prototype pollution, path traversal, regular-expression denial of service, command and template injection in Node packages: the corpus is weighted towards the kinds of flaws that were getting CVEs in the npm ecosystem in the years before 2020. For a static analyser, that is a fair exam, and the paired-patch design is a real improvement over counting raw findings.

It is also specific about the target. A tool is credited with identifying the vulnerability itself, not with producing findings somewhere in a repository that happens to contain one. That matters more for AI reviewers than for SAST, because a language model can produce a plausible paragraph about “input validation concerns” without ever pointing at the line.

What it is not: the gaps that matter for AI review

Here is where a 2026 buyer should slow down. The benchmark was designed to evaluate static analysis tools. An AI code reviewer is a different kind of instrument, and the benchmark misses it in four ways.

  1. It is a whole-repository scan, not a pull-request review. The benchmark hands a tool the entire vulnerable codebase. A PR reviewer sees a diff and whatever context it can pull in. The question that matters to an engineering team — would this reviewer have caught the bug in the pull request that introduced it? — is not the question the benchmark asks. The context post explains why that distinction dominates real-world accuracy.
  2. It is JavaScript and TypeScript only. If your code is Go, Python, Java or Rust, a score on this benchmark tells you how a tool handles npm-style vulnerabilities and nothing about yours.
  3. The corpus is public and old. Every CVE in it, with its fix, has been on the internet for years. Modern models have almost certainly seen the fixing commits during training. A reviewer that “detects” a 2018 lodash vulnerability may be recalling it rather than reasoning about it, and that says little about a novel bug in your private repository. This is the single biggest reason to treat any LLM score on this benchmark with suspicion.
  4. It does not score severity, explanation or fix quality. A SAST tool emits a rule ID. An AI reviewer writes a comment that a human has to read, trust and act on. Whether that comment is correct, proportionate and actionable is where AI review lives or dies, and the benchmark has no column for it.

None of this makes the benchmark bad. It makes it a benchmark for SAST, which is what it was built to be. The error is in the marketing that cites it as proof an LLM reviewer is accurate, a claim we examined more broadly in how accurate AI code review is.

Borrow the method, not the number

The benchmark’s structure is the useful export: real vulnerability, real fix, score both states, insist on location. You can apply exactly that to a PR reviewer on your own repositories, in your own languages, with code the model has not seen. It takes an afternoon and gives you a number you can defend in a purchasing conversation.

  1. Collect ten to twenty real security fixes from your own history. Search merged pull requests for the words you would expect — sanitize, escape, authz, permission, injection, CVE — and for dependency bumps that cited an advisory. Keep the ones where the fix is small and the vulnerability is clear in the diff.
  2. Reconstruct the introducing change. For each fix, find the pull request that originally added the vulnerable code. That PR is your test case; the fix tells you where the finding must land.
  3. Replay it through the reviewer. Open the introducing change as a fresh pull request on a branch, let the reviewer run, and record whether it commented on the vulnerable lines, what severity it assigned, and whether the explanation was correct. Most self-hosted tools make this easy because you control the repository; with PURA the replay runs inside your own infrastructure, so nothing about the exercise leaves your network.
  4. Replay the fix too. Open the fixing change as a PR as well. A reviewer that keeps flagging the now-correct code, or that objects to the fix, is telling you its false-positive behaviour on exactly the code you ship.
  5. Add ten ordinary PRs as controls. Changes with no security content. Count every security finding the reviewer raises on them; that is your noise floor, and it is what your engineers will experience every day.
  6. Score it like the benchmark does. Detections at the right location over total vulnerabilities; findings on patched and control PRs over total such PRs. Two numbers, no averaging.

Run the same set against two or three candidates and the comparison is concrete. It also exposes a trade-off the public benchmark cannot: a reviewer tuned for recall will find more of your twenty bugs and also comment on more of your ten clean PRs. Which side of that line you want is a team decision, and the blocking versus advisory post is about making it deliberately.

Reading a vendor’s benchmark claim

Three questions separate a meaningful citation from a slide-deck one:

  • Which state did they score? A detection rate quoted without the false-positive rate on the patched code is half the benchmark. Ask for both.
  • Whole repo or pull request? If the tool was pointed at the full vulnerable checkout, the result does not transfer to PR review. If they built a PR-shaped harness, ask to see it.
  • Was the model trained after the corpus was public? For any LLM-based tool the answer is yes, which is why a private replay on your own code is the only score you should weight heavily.

Where this leaves security benchmarking in 2026

The OpenSSF CVE Benchmark did something genuinely useful: it made “real bugs, real fixes, both scored” the standard for evaluating security tooling, and it did so with a clean, extensible design. What the industry has not yet produced is the equivalent for AI pull-request review — a held-out, multi-language, PR-scoped corpus with human-rated explanations. Until one exists, the method is portable and the number is not. Borrow the method, run it on your own repositories, and treat any single public score, including ones that flatter the tool you already like, as a conversation starter rather than a result. The broader picture of what AI review reliably catches and structurally misses is in our security coverage post.

Frequently asked questions

What is the OpenSSF CVE Benchmark?
An open source benchmark from the OpenSSF Security Tooling working group, announced in December 2020. It contains over 200 real, validated vulnerabilities from published CVEs in open source JavaScript and TypeScript projects, each recorded in both its vulnerable and its patched state, with drivers for ESLint, CodeQL and NodeJsScan.
How does the OpenSSF CVE Benchmark score a security tool?
A tool is run against the pre-patch and the post-patch code. Detection is whether it identifies the vulnerability in the vulnerable version; the false-positive measure is whether it still flags the same code once the fix is applied. Both numbers matter, and a vendor quoting only the first is quoting half the result.
Can the OpenSSF CVE Benchmark be used to evaluate AI code review tools?
Only with care. It was designed for whole-repository static analysis, covers one language ecosystem, and its CVEs and fixes have been public for years, so a modern model may have seen them in training. The method - real vulnerability, real fix, score both states - transfers well; a public score on it does not say much about a pull-request reviewer on your private code.
How do I benchmark an AI code reviewer on my own repositories?
Collect ten to twenty real security fixes from your own merged pull requests, reopen the change that introduced each vulnerability as a fresh PR and run the reviewer, then do the same with the fix and with a set of ordinary PRs as controls. Score detections at the right location, and findings on patched and control PRs, as two separate numbers.

Ready to put your AI review spend on rails?

Install PURA on your GitHub repos and start setting budgets in minutes — not months.

Install PURA for free