VLoc Bench: Can Agents Find Vulnerable Code at Repository Scale?

When security engineers investigate a vulnerability, one of their first questions is simple: which files contain it?

Most cybersecurity benchmarks skip this step. They give models the relevant code or tell them where the vulnerability is, then test whether they can detect, repair, or exploit it.

Today, we're releasing the Vulnerability Localization Benchmark (VLoc Bench) to test whether agents can find vulnerable files on their own. Given only a weakness class and read-only access to a repository, an agent must identify the affected files, or, once the repository has been patched, correctly report that the weakness is no longer present.

Our results show that vulnerability localization is far from solved. The strongest system achieves just 0.229 File F1, and on 38.4% of tasks, none of the models find a single correct file. We also find a key tradeoff: the systems best at finding vulnerabilities are not necessarily the best at recognizing when a repository has already been patched.

Inside VLoc Bench

Every task is built from a GitHub Security Advisory, a public record linking a CWE class to a repository and the commit that fixed it. From that commit we take two snapshots: the pre-push state, which still contains the vulnerability, and the post-push state, which contains the fix. Ground-truth labels come from the patch diff deterministically: every implementation file the fix touched, minus tests, docs, and config. What is left is 500 tasks from advisories disclosed between 2016 and 2026.

500
Tasks
290
Repositories
147
CWE classes
6
Ecosystems

The model never sees the advisory. It receives the generic MITRE description of one weakness class, with no advisory text, no CVE identifier, no fixing commit, no file hint, and no line range. Because a weakness class says what kind of vulnerability to look for but nothing about where it lives, every file the agent names has to come out of its own search.

Two phases, one interface

The paired snapshots let each task be scored twice, under an identical prompt, toolset, and command budget. Only the repository state changes.

Phase A · node-saml/xml-crypto · CVE-2024-32962
$ ls src/
signed-xml.ts  utils.ts  validator.ts

$ grep -r "verifySignature" src/
src/signed-xml.ts: verifySignature(cert) {

$ cat src/signed-xml.ts | head -30
export class SignedXml {
  verifySignature(cert) {
    // ⚠️ Only checks signature validity
    // Missing: authorization check
    return this.validateSignature(cert);
  }
}

> submit_vulnerable_files
["src/signed-xml.ts"]
✓ Correct! F1 = 1.0
Phase B · same commands, patched repository
$ cat src/signed-xml.ts | head -30
export class SignedXml {
  verifySignature(cert) {
    // ✓ Now checks signature validity
    return this.validateSignature(cert);
  }
}

> submit_vulnerable_files
No Vulnerability

The interface and the metrics

Every system runs against the same read-only terminal (file listing, text search, file viewing, metadata queries) in a fresh, network-disabled container. The agent ends a task by calling submit_vulnerable_files with a ranked list of paths, or submit_no_vulnerability_found. It gets 15 commands and 20 turns, and every score is the mean of three runs.

File F1 (Phase A)
Harmonic mean of file-level precision and recall against the patch-derived labels. Submitting nothing scores 0, and precision matters as much as recall, so a model cannot succeed by dumping half the repository into its answer.
True negative rate (Phase B)
Fraction of patched repositories where the model correctly submits no file. Ground truth is empty by construction, so any path submitted there is a false positive.

What is in the 500 tasks

The distribution follows the advisory database rather than a balanced sample, so Go dominates and Composer contributes a single task. Repositories range from 12 KB to 840 MB; the median task has three ground-truth files.

Package ecosystem
tasks · n=500
CVSS severity
tasks · n=500

The Leaderboard

We evaluated 27 language models, plus four static-analysis tools as baselines, all under the same prompt, tools, and budget. The models span frontier closed-source systems, open-weight models from 350M to 753B parameters, and models trained specifically for code search or vulnerability localization.

Phase A: File F1 across 31 systems
mean of 3 runs · 500 tasks · higher is better
Frontier (closed) Open-weight ≥20B Open-weight <20B Static analysis
The chart mixes general-purpose models and static analyzers, so the ordering compares approaches to repository search rather than raw capability.
View full results table (File F1, precision, recall)
SystemParamsFile F1PrecisionRecall

Parameter count is a weak predictor

Larger systems often underperform smaller ones in both open-weight and closed-source families. Llama-3.3-70B scores 0.012 while the 2B Gemma-4-E2B scores 0.039, Qwen3.5-122B ties Qwen3.5-27B at 0.091, and GPT-5 Mini beats GPT-5, which is consistent with GPT-5's system card reporting greater conservatism on dual-use cybersecurity tasks. General software-engineering capability is not a reliable proxy here: a system can underperform because safety alignment constrains dual-use work, or because security reasoning is out of distribution relative to its coding training.

Task-specific training is the sharpest illustration. Antares-3B, our own 3B model trained for agentic vulnerability localization, reaches 0.223 File F1, second overall and ahead of GPT-5.5 at default reasoning effort. Antares-350M scores 0.135 at 350M parameters, above every general-purpose open-weight model except the 753B GLM-5.2. Fitted across the general-purpose open-weight models alone, the parameter-count trend is positive but weak (r=0.50), and the specialized models sit well off it.

Static analyzers are a real baseline

Semgrep at 0.086 File F1 outperforms most of the open-weight models we tested, including two above 100B parameters. General-purpose models under 20B do worse still: CodeScout-14B, the best of them at 0.044, scores about half what Semgrep does. The systems that clear Semgrep by a wide margin are either frontier models or trained for this task.

Finding Vulnerabilities Is Not the Same as Knowing When Not To

Phase B reverses the question. The repository has been patched; the recorded vulnerability is gone; the correct answer is to report no file. Ranking by true negative rate produces a substantially different ordering than Phase A, which is the most consequential finding in the release.

Localization vs. restraint
Phase A File F1 (x) vs. Phase B true negative rate (y) · 31 systems · hover for values
Frontier (closed) Open-weight ≥20B Open-weight <20B Static analysis
Scroll the chart sideways to see the full range. The upper-right region, where strong localization meets strong restraint, is empty. GPT-5.5 and the Antares models sit at the lower right: the strongest localizers in the set, and the least willing to hold back. Antares-1B reports files on 99% of already-patched repositories. GPT-5 Nano and the Granite base models sit at the upper left, the reverse. The static analyzers sit at the upper left too, clearing 91.2% to 99.6% of patched repositories while never exceeding 0.086 File F1.
Two caveats on these numbers. A run that exhausts its turns, hits an API error, or refuses on safety grounds is credited as a correct clean verdict, so every unrecoverable trajectory becomes a true negative and none becomes a false positive. TNR for hosted models is therefore entangled with the provider's safety layer to a degree we have not separated. And in 52 of 499 pairs the patch itself adds the advisory identifier or a link to an advisory database, so the clean verdict can be read off the repository rather than inferred from the code.

The contrast shows up even within one family. GPT-5.5 (xhigh) leads Phase A at 0.229 File F1 but reports files on 72% of already-patched repositories. GPT-5 Nano is the mirror image: 0.024 File F1, but it correctly clears 86.8% of patched repositories.

The Granite base models make the caveat explicit. Granite-4.0-1B posts a perfect 1.000 true negative rate and 0.000 File F1: it never submits a file anywhere, so it is right by default on patched code and wrong everywhere else. Reading either phase alone rewards a degenerate strategy: score only localization and you favor systems that report broadly; score only patched repositories and you favor systems that never commit.

This matters beyond the leaderboard. Alert fatigue is a persistent operational problem, so localization that improves without preserving the ability to recognize already-patched code is not something a security team can use. False-positive control belongs in the definition of capability, not in a footnote.

View Phase B results table (true negative rate)
SystemParamsTNRPhase A F1

What Makes Localization Hard

Aggregate scores say how well systems do, not why tasks are hard. To separate the two, we fit a Lasso regression predicting per-task File F1 from 52 repository and metadata features available before any model runs.

Repository structure carries 4.5× the predictive weight of model identity, and a model-only regression explains almost nothing about which tasks get solved. The strongest single predictor is code concentration: repositories whose lines sit in a few large files are easier. Larger repositories, deeper trees, and Go projects score lower, while the number of ground-truth files carries negligible weight. How the code is organized matters more than how many files you have to find.

File F1 by repository size
mean across all evaluated models · 500 tasks
Performance falls roughly 10× from the smallest repositories (<100 KB, n=20) to the largest (10+ MB, n=223), and 63% of tasks fall in the two hardest buckets.

Scale and ecosystem interact, and the interaction is clearest in the unsolved set. In 38.4% of tasks, every model scores File F1 = 0; large Go and Maven repositories account for 47% and 31% of that subset, and Go alone is 43% of the benchmark. Adding models or parameters does not dissolve it.

How Runs Fail

File F1 collapses very different behaviors into one number: a run that stops after two commands and a run that submits a dozen wrong files both score 0. So we label every non-perfect Phase A trial, about 38,500 of them, from its trace, using command counts, precision, recall, and submission status rather than a model judge.

Failure mode distribution
share of non-perfect Phase A trials · all models × 3 runs
Abstained (59.1%): no files submitted Submitted (40.9%): files submitted, not correct
Exhausted budget and wrong files together are 59.7% of all failures: searching without deciding, and deciding without finding.

Two categories dominate. Exhausted budget (32.3%) is a run that issues at least 13 of its 15 commands and never submits: search that does not converge within the horizon. Wrong files (27.4%) is the opposite: a confident submission with no overlap with the ground truth.

Premature termination (16.9%), stopping after at most three commands, is concentrated among smaller systems. Partial recall (8.5%) is the most encouraging failure and more common among stronger systems: the run finds at least one relevant file but misses others, so multi-file localization stays hard even when the search reaches the right code.

Across models, mean commands per task correlates with mean File F1 at r=0.72 (p<0.001): weaker systems stop early, stronger ones keep searching. Higher performers also spend more of that budget on targeted search and file reading (rg, grep, cat) than on directory listing, and reliability gates everything: tool-error rates above 15% coincide with lower scores, because failed commands consume budget without yielding evidence.

Run It Yourself

The benchmark, the harness, and the analysis code are public. All 500 tasks download from public GitHub repositories at the recorded commit SHAs, with no gated access, and each is verified against a deterministic content hash, so a snapshot either matches the manifest or fails loudly.

bash
git clone https://github.com/cisco-foundation-ai/vulnerability-localization-benchmark.git
cd vulnerability-localization-benchmark
pip install -e .

# Build the sandbox image the agent runs inside
docker build -t vulnerability-localization-benchmark-sandbox .

# Fetch and verify all 500 paired repository snapshots
python data/downloader_and_verifier.py --source-dir /path/to/dataset/

Then evaluate each phase: Phase A on the vulnerable snapshots, Phase B on the patched ones.

bash
# Phase A - localization on vulnerable repositories
PYTHONPATH=src python3 -m vulnerability_localization_benchmark.cli \
    --config configs/default.yaml --api-base http://localhost:8200/v1 \
    --model-name your-model --runner vllm --output-dir results/my-run \
    --phases a --workers 16

# Phase B - verification on patched repositories
PYTHONPATH=src python3 -m vulnerability_localization_benchmark.cli \
    --config configs/default.yaml --api-base http://localhost:8200/v1 \
    --model-name your-model --runner vllm --output-dir results/my-run \
    --phases b --workers 16

What a full sweep costs

A full 500-task Phase A sweep spans a 170× cost range, from $0.60 for Antares-350M on a single H100 to $141 for GPT-5.5 xhigh through the OpenAI API. Open-weight models up to 31B parameters, served with 16 workers on one H100, finish in under an hour, cheap enough to sit inside a CI stage.

SystemRuntimeTotal costCost / task
Antares-3B (local, H100)~15 min$0.82$0.002
Antares-1B (local, H100)~13 min$0.71$0.001
Antares-350M (local, H100)~11 min$0.60$0.001
GLM-5.2 (OpenRouter API)~50 min$12.50$0.025
GPT-5.5 xhigh (OpenAI API)~5 hrs$141.00$0.282

Cost is also why some models are missing: a standardized sweep would exceed $600 at Claude Opus 4.8 pricing, and an unconstrained agentic configuration using Claude Code with subagent spawning costs $1,658 for the same 500 tasks. We will add these as budget permits.

Contributors
Aman Priyanshu*,1, Supriti Vijay*,1, Kimia Majd*,1, Xuhong He1,3,†, Fraser Burch1, Takahiro Matsumoto1, Jianliang He1,2,†, Baturay Saglam1,2,†, Arthur Goldblatt1, Zhuoran Yang1,2,†, Amin Karbasi1
1 Foundation AI, Cisco Systems Inc.  ·  2 Yale University  ·  3 Carnegie Mellon University
* Equal contribution  ·  Work done while at Foundation AI