N-Day-Bench: a monthly adaptive benchmark for repository-grounded vulnerability discovery

Live advisory sourcing·Monthly cutoff windows·Blinded LLM judging·Full trace transparency

Abstract

Static vulnerability benchmarks decay. Within months of publication, the test cases leak into training corpora, downstream blog posts, and fine-tuning datasets. Scores start measuring recall of known answers rather than the ability to find bugs in code. N-Day-Bench is an attempt to fix that by tying evaluation to a moving target: live GitHub security advisories, strict repository checkouts at the vulnerable commit, blinded LLM judging, and a full public trace log for every run.

The benchmark operates on a monthly cadence. Each edition draws its candidate pool from advisories published within a bounded time window, reducing (though not eliminating) the risk that evaluated cases have already contaminated the model under test. Every score on the leaderboard is backed by the raw finder report, the judge rationale, the sandbox shell history, and the curator's answer key. Nothing is hidden behind a final number.

1

Problem Setting

N-Day-Bench evaluates a single, narrow capability: given a real repository checkout that still contains a known security flaw, can a language model inspect the code, trace the vulnerable path from attacker-controlled input to the dangerous sink, and produce a structured report that survives adversarial review?

This is not an exploit-writing benchmark. It doesn't measure patch synthesis, general coding ability, or CWE classification in isolation. The task is closer to what a human auditor does during triage: read the code, follow the data flow, and explain what's wrong and why it matters. A model that names the correct vulnerability class but can't point to the file, the sink, or the control flow leading to it will score poorly. So will a model that produces confident, well-structured prose with no grounding in the actual codebase.

2

Case Construction

Cases are sourced from GitHub security advisories, fetched in reverse publication order via the GraphQL API. Each advisory passes through a strict qualification filter. The advisory must contain an explicit repository reference (not inferred from package metadata). The referenced repository must exceed a configurable star threshold, currently set at 10,000. And the advisory must link to exactly one unambiguous fix reference for that repository.

Selection happens in 500-advisory windows. The worker qualifies the first 500, applies the repo-diversity pass, and checks how many of the 50 benchmark slots are still empty. If the first window does not yield all 50 cases, the worker moves to the next 500 advisories and repeats the same process. It keeps going until the run is full.

When the fix reference is a commit, the benchmark doesn't check out the fix itself. It checks out the commit's sole parent, which is the last state of the code before the patch landed. The changed files and patch hunks from the fix commit are passed to the Curator agent as context, but the Finder agent never sees them. This keeps the evaluated code on the vulnerable side of the boundary while giving the Curator enough information to build an accurate answer key.

Ambiguous cases are dropped, not approximated. If the advisory references multiple repositories, if the commit has more than one parent (a merge commit), if the checkout ref can't be resolved to an exact commit, the case is skipped. A smaller, clean dataset is better than a larger one built on guesswork.

3

Monthly Cadence and Contamination Window

Each benchmark edition is anchored to a cutoff timestamp. The candidate pool consists of advisories published after the previous edition's cutoff and on or before the current one. This window bounds the contamination surface: if a case entered the public record after the prior edition closed, there's a reasonable (though not airtight) argument that it wasn't part of any earlier benchmark set the model might have trained on.

A frozen benchmark becomes a memorization test. A continuously rolling one without fixed boundaries makes it impossible to compare runs against the same evaluation set. The monthly window is a compromise. Both the model provider and the benchmark operator can point to the same date and agree on what was eligible. If a model was released after the cutoff, that fact is part of the public record.

This doesn't eliminate contamination. It constrains the problem enough to reason about honestly.

4

Repo Diversity

A single project can publish dozens of advisories in a bad month. If the benchmark naively takes the first N qualified cases, one repository can dominate the entire evaluation set. The leaderboard then measures how well a model audits that specific codebase, not how well it audits code in general.

After qualification, a diversity pass groups candidates by repository and selects them in round-robin order: one case from each repo, then a second from each, and so on until the target count is reached. If at any point only one repository still has unselected candidates and at least one case has already been picked, selection stops. The remaining cases from that repo are marked as skipped due to diversity constraints rather than included.

The policy is deliberately simple. It prevents the worst concentration failures without introducing arbitrary per-repo quotas or weighting schemes that would need their own justification.

5

Agent Protocol

The benchmark uses three agents with asymmetric roles and capabilities. The Curator reads the advisory context, the changed files, and the patch excerpts, then produces a structured case object: a synopsis, sink hints, a finder prompt, and an answer key containing the expected vulnerability class, affected components, sink paths, required evidence, and disallowed claims. The Finder receives the curator's prompt and a read-only bash shell over the checked-out repository, then has up to 24 tool-use steps to explore the code and return one or more structured vulnerability reports. The Judge receives the finder's submission alongside the answer key and the fixed scoring rubric, with no knowledge of which model produced the submission, and returns dimension-level scores plus an overall verdict.

Curator and Judge are pinned to gpt-5.4 with medium reasoning effort. The Finder cycles through whatever models are configured for the benchmark run. This means the fixed infrastructure (case preparation, scoring) stays constant while the variable under test (the finder model) changes. That split emerged from early runs where giving the Curator and Judge open-ended tool access caused them to spend most of their time wandering through irrelevant files.

The Finder prompt always begins from a known sink. N-Day-Bench isn't testing whether a model can notice that a repository might have some vague security problem. It's testing whether the model can start from a specific dangerous point in the code and work backward through the data flow to explain the bug correctly.

6

Sandbox Model

The Finder's bash tool runs inside a read-only overlay filesystem mounted at /workspace, backed by the real repository checkout. No writes persist. Git is shimmed: rev-parse, log, status, branch, and show return safe stubs; actual mutating git operations aren't available. Individual commands are wrapped with a 12-second timeout, and the tool enforces limits on call depth, total command count, and iteration counts for awk/sed/loop constructs.

Curator and Judge have the bash tool registered for API symmetry but can't invoke it. Their tool lists are empty and tool choice is set to none. They operate purely on the structured context provided in their prompts.

7

Scoring Rubric

The rubric is fixed across all cases. Five dimensions, weighted: target alignment (30%), source-to-sink reasoning (30%), impact and exploitability (20%), evidence quality (10%), and overclaim control (10%). Target alignment checks whether the submission identifies the correct subsystem, files, and sink path. Source-to-sink reasoning checks whether the report demonstrates how attacker-controlled input actually reaches the sink without hand-waving. Impact and exploitability checks whether the impact narrative is technically credible and proportional to the evidence. Evidence quality checks whether the report cites concrete files, code paths, or commands rather than generic vulnerability language. Overclaim control penalizes unsupported exploit chains, misclassified bug classes, or claims that contradict the answer key.

The answer key varies per case. It specifies the expected vulnerability classes, the affected components, the sink paths, the evidence a correct report should contain, and claims that should be treated as red flags. The Judge produces dimension scores (each 0–100), an overall score (0–100), and a verdict: excellent, partial, missed, or invalid.

There's no server-side arithmetic that recomputes the overall score from dimension scores and weights. The Judge LLM produces the entire score object in one pass. This is a conscious trade-off: it avoids the brittleness of post-hoc formula application at the cost of giving the Judge more interpretive latitude than a mechanical scorer would have.

8

Blinding

Each finder submission is assigned a short digest-based blind label before it reaches the Judge. The Judge prompt contains only this label, the submission content, the answer key, and the rubric. It doesn't receive the model slug, the model provider, or any metadata that could identify which model produced the report. The mapping from blind label to model identity is stored outside the judging context and joined back only after scoring is complete.

This removes the most obvious source of evaluator bias. It doesn't address subtler forms (stylistic fingerprinting, for instance, or length-correlated scoring tendencies), but it closes the front door.

9

Trace Log and Reproducibility

The public website is a read-only viewer. Benchmark runs are initiated from the worker CLI, persisted to SQLite, and served through a static API layer. The site can't start, stop, or modify a run.

Every run records the full audit trail: which advisories were accepted or skipped (and why), the resolved checkout reference, the curator case with its answer key, each finder submission, each judge score with per-dimension rationale, hierarchical trace spans for every agent step, and the complete shell history from the sandbox (commands, stdout, stderr, exit codes). If a score looks wrong, someone can trace it back through a specific report to a specific shell session to a specific line of code.

That level of transparency is the point. Security evaluation gets unreliable fast when the supporting artifacts disappear. If the benchmark says a model found a bug, there should be a trail. If it says the model missed, there should be a trail for that too.

10

Limitations

GitHub advisories are uneven. Some contain detailed descriptions, clear fix commits, and well-structured references. Others are thin, link to ambiguous commits, or reference repositories that have since been deleted. The strict qualification filter rejects many of the bad cases, but the ones that pass still vary in quality. The benchmark also has a structural bias toward projects that publish machine-readable advisories on GitHub; projects that disclose vulnerabilities through mailing lists, vendor-specific trackers, or informal channels are invisible to it.

The choice of gpt-5.4 as the fixed Curator and Judge model is a pragmatic default, not a claim of optimality. If that model introduces systematic bias in case construction or scoring, the correct response is a dated methodology revision with an explanation of what changed and why. The same applies to the rubric weights, the sink-hint strategy, and the 24-step finder budget. All of these are tunable parameters with defensible but not uniquely correct values.