What the results mean in practice
An AI security engine is a model inside a harness.
Deterministic SAST and AI review covered different ground; what an AI engine reported depended on its harness as much as on its model; and coverage and cost were only loosely related.
- 01Open the evidence
SAST and AI review cover different ground
Snyk Code matched 82.4% (89 of 108) and Claude Code /security-review with Opus 5 xhigh 79.3% (85 of 108). They disagree on 28 vulnerabilities, 16 matched only by Snyk Code and 12 only by Opus 5 xhigh; a corpus of this size cannot separate them.
Together they match 101 of 108, as many as all seven endpoint-aware configurations combined. The best pair without SAST, Opus 5 xhigh with Codex Security GPT-5.6 Terra, reaches 89 (93 under many-to-one credit).
Snyk Code adds 16 vulnerabilities to Opus 5 xhigh, only 3 of them cross-file, led by open redirect (6). Opus 5 xhigh adds 12 to Snyk Code, 7 of them cross-file, including the authorization classes.
Snyk Code is the only one of the seven endpoint-aware configurations with unique coverage: 10 vulnerabilities in six classes (5 under many-to-one credit).
Outside the reference set, in this run, AI configurations found at least seven real vulnerabilities in scored classes that the reference set did not contain and Snyk Code did not report.
Interpret with care: A union across configurations is a ceiling, not one tool's result. Combining the two also combines their queues: 539 findings for 101 matches.
- 02Open the evidence
The harness decides what gets reported
Claude Code's /security-review excludes ReDoS and reports prototype pollution and open redirect only at extremely high confidence. On the 20 reference vulnerabilities in those classes, Snyk Code matched 18 and Opus 5 xhigh 9; on the 81 others (excluding 7 cross-site scripting vulnerabilities in React and Angular applications), Opus 5 xhigh matched 71 and Snyk Code 67.
In a supplementary run on 19 of the 20 applications, the same model at the same effort, without that policy, matched 16 of the 20.
Codex Security with GPT-5.6 Sol located 80 vulnerabilities at file level but 34 under the two-line rule, typically pointing above the dangerous call.
DeepSec's model-free scan stage queued a file from only 56 of the 108 flows before any model ran.
The model still matters inside a harness: under the same harness, effort and prompt, Opus 5 matched 14 vulnerabilities that Sonnet 5 missed, against 2 the other way.
Interpret with care: The policy reading rests on the policy text and one supplementary control run; harness and model cannot be fully separated by this design.
- 03Open the evidence
Coverage and cost were only loosely related
Snyk Code scanned all 20 applications in 8 minutes; the comparable AI configurations took between 2.4 hours and 8.9 hours.
Within Codex Security, all at xhigh effort, GPT-5.6 Sol cost 35.0 times as much as GPT-5.6 Luna and matched 11 fewer vulnerabilities: a comparison of model tiers, not of reasoning effort. Within Claude Code /security-review, at the same xhigh effort and with the same prompt, Opus 5 cost 4.2 times as much as Sonnet 5 and matched 12 more.
Known cost per matched vulnerability ranged from $0.47 to $21.92.
Interpret with care: One run per configuration and application: every ratio is a single observation. Snyk Code has no per-scan model cost; its license cost is outside this study.
- 04Open the evidence
The top two hold; the middle reorders
Snyk Code and Opus 5 xhigh are the two highest-ranked endpoint-aware configurations under every one of the 20 alternative scoring rules; Snyk Code ranks first under 18 and Opus 5 xhigh under the other two; their order should not be read as a result.
Line tolerance is the main driver of reordering: widening it from ±2 to ±10 lines adds 37 matches for Codex Security with GPT-5.6 Sol, 28 for Terra and 16 for Luna, at most 3 for any Claude Code configuration, and none for Snyk Code.
Interpret with care: Rescoring shows which conclusions survive changes in the scoring rule; it does not add statistical power.
Research question
Who finds which vulnerabilities?
When security teams point AI coding agents or AI security harnesses at real applications, what do they find that deterministic SAST does not, and what do they miss that it catches?
We lead with recall, because the question practitioners ask of a scanner is whether it finds the vulnerabilities that are actually there; precision and cost are reported beside it.
Benchmark design and configurations
Nine configurations, one blind protocol
Each of the 9 configurations ran once on each of the 20 applications, for 180 successful runs. No configuration received an advisory, a class hint or the reference set.
Every result belongs to a complete harness and model configuration, never to a model alone.
| Configuration | Attacker-Reachable Vulnerability Recall (macro, matched) | 95% interval | Precision against the reference set (lower bound) | Matched at the exact line |
|---|---|---|---|---|
| Snyk Code | 82.4% (89 of 108) | 74.0–90.5% | 20.9% | 85 |
| Claude Code /security-review · Opus 5 xhigh | 79.3% (85 of 108) | 71.6–86.7% | 74.6% | 79 |
| Claude Code /security-review · Opus 5 medium + Snyk MCP | 75.2% (80 of 108) | 68.2–82.3% | 82.5% | 74 |
| Claude Code /security-review · Sonnet 5 xhigh | 67.0% (73 of 108) | 57.7–76.2% | 74.5% | 55 |
| Codex Security · GPT-5.6 Luna | 41.2% (45 of 108) | 26.6–56.5% | 20.8% | 15 |
| Codex Security · GPT-5.6 Terra | 30.1% (35 of 108) | 19.1–41.9% | 15.8% | 6 |
| Codex Security · GPT-5.6 Sol | 29.2% (34 of 108) | 18.1–41.1% | 12.7% | 2 |
An empty cell means not applicable or unavailable as stated in `columns`; it never means zero.
| Configuration | Localized recall (macro, matched) | 95% interval | Precision against the reference set (lower bound) |
|---|---|---|---|
| DeepSec · Opus 5 xhigh | 37.5% (37 of 108) | 22.6–53.2% | 7.1% |
| DeepSec · GPT-5.6 Sol xhigh | 2.5% (1 of 108) | 0.0–7.5% | 10.0% |
Interpretation boundary: the interval shows how much a score depends on which applications are in the corpus, not run-to-run variation.
Central result
Close at the top. Too close to separate.
A corpus of this size cannot separate the top two: a split as close as 16 to 12 would need a corpus many times larger before it could indicate a real difference, and not separating them is also not evidence that they are equal. Snyk Code ranks first in 74% of the resampled corpora.
The three Codex Security configurations matched between 34 and 45 vulnerabilities; much of that gap is about which line they report, not whether they see the vulnerability.
View exact values
| Configuration | Attacker-Reachable Vulnerability Recall (macro, matched) | 95% interval | Precision against the reference set (lower bound) | Matched at the exact line |
|---|---|---|---|---|
| Snyk Code | 82.4% (89 of 108) | 74.0–90.5% | 20.9% | 85 |
| Claude Code /security-review · Opus 5 xhigh | 79.3% (85 of 108) | 71.6–86.7% | 74.6% | 79 |
| Claude Code /security-review · Opus 5 medium + Snyk MCP | 75.2% (80 of 108) | 68.2–82.3% | 82.5% | 74 |
| Claude Code /security-review · Sonnet 5 xhigh | 67.0% (73 of 108) | 57.7–76.2% | 74.5% | 55 |
| Codex Security · GPT-5.6 Luna | 41.2% (45 of 108) | 26.6–56.5% | 20.8% | 15 |
| Codex Security · GPT-5.6 Terra | 30.1% (35 of 108) | 19.1–41.9% | 15.8% | 6 |
| Codex Security · GPT-5.6 Sol | 29.2% (34 of 108) | 18.1–41.1% | 12.7% | 2 |
An empty cell means not applicable or unavailable as stated in `columns`; it never means zero.
View exact values
| Configuration | Localized recall (macro, matched) | 95% interval | Precision against the reference set (lower bound) |
|---|---|---|---|
| DeepSec · Opus 5 xhigh | 37.5% (37 of 108) | 22.6–53.2% | 7.1% |
| DeepSec · GPT-5.6 Sol xhigh | 2.5% (1 of 108) | 0.0–7.5% | 10.0% |
Complementarity
Two engines reach the ceiling
Snyk Code matches 89; Opus 5 xhigh adds the 12 vulnerabilities that it matched and Snyk Code did not, reaching 101. After those two, no other configuration adds a vulnerability. Opus 5 xhigh also misses 16 vulnerabilities that Snyk Code matched, which the cumulative count does not show.
Under many-to-one credit, Snyk Code's unique coverage falls to 5 and the best pair of AI configurations reaches 93, while the combined ceiling of 101 holds.
The authorization classes illustrate the split: on the three IDOR and mass-assignment vulnerabilities, Snyk Code matched none and the Claude Code configurations matched two or three. In the other direction, Snyk Code matched all 11 open redirects, all 6 prototype-pollution vulnerabilities and all 16 path traversals.
View exact values
| Step | Configuration | Vulnerabilities added at this step | Cumulative matched |
|---|---|---|---|
| 1 | Snyk Code | 89 | 89 |
| 2 | Claude Code /security-review · Opus 5 xhigh | 12 | 101 |
| 3 | Claude Code /security-review · Opus 5 medium + Snyk MCP | 0 | 101 |
| 4 | Claude Code /security-review · Sonnet 5 xhigh | 0 | 101 |
| 5 | Codex Security · GPT-5.6 Luna | 0 | 101 |
| 6 | Codex Security · GPT-5.6 Terra | 0 | 101 |
| 7 | Codex Security · GPT-5.6 Sol | 0 | 101 |
An empty cell means not applicable or unavailable as stated in `columns`; it never means zero.
View exact values
| Configuration A | Configuration B | Matched by either | B adds to A | A adds to B | Combined findings to triage |
|---|---|---|---|---|---|
| Snyk Code | Claude Code /security-review · Opus 5 xhigh | 101 | 12 | 16 | 539 |
| Snyk Code | Claude Code /security-review · Opus 5 medium + Snyk MCP | 100 | 11 | 20 | 522 |
| Snyk Code | Claude Code /security-review · Sonnet 5 xhigh | 99 | 10 | 26 | 523 |
| Snyk Code | Codex Security · GPT-5.6 Luna | 95 | 6 | 50 | 641 |
| Snyk Code | Codex Security · GPT-5.6 Terra | 94 | 5 | 59 | 646 |
| Snyk Code | Codex Security · GPT-5.6 Sol | 93 | 4 | 59 | 692 |
| Claude Code /security-review · Opus 5 xhigh | Codex Security · GPT-5.6 Terra | 89 | 4 | 54 | 335 |
| Claude Code /security-review · Opus 5 xhigh | Codex Security · GPT-5.6 Luna | 88 | 3 | 43 | 330 |
| Claude Code /security-review · Opus 5 xhigh | Codex Security · GPT-5.6 Sol | 88 | 3 | 54 | 381 |
| Claude Code /security-review · Opus 5 xhigh | Claude Code /security-review · Sonnet 5 xhigh | 87 | 2 | 14 | 212 |
| Claude Code /security-review · Opus 5 medium + Snyk MCP | Claude Code /security-review · Opus 5 xhigh | 85 | 5 | 0 | 211 |
| Claude Code /security-review · Opus 5 medium + Snyk MCP | Claude Code /security-review · Sonnet 5 xhigh | 85 | 5 | 12 | 195 |
| Claude Code /security-review · Opus 5 medium + Snyk MCP | Codex Security · GPT-5.6 Terra | 85 | 5 | 50 | 318 |
| Claude Code /security-review · Opus 5 medium + Snyk MCP | Codex Security · GPT-5.6 Luna | 84 | 4 | 39 | 313 |
| Claude Code /security-review · Opus 5 medium + Snyk MCP | Codex Security · GPT-5.6 Sol | 84 | 4 | 50 | 364 |
| Claude Code /security-review · Sonnet 5 xhigh | Codex Security · GPT-5.6 Luna | 78 | 5 | 33 | 314 |
| Claude Code /security-review · Sonnet 5 xhigh | Codex Security · GPT-5.6 Terra | 78 | 5 | 43 | 319 |
| Claude Code /security-review · Sonnet 5 xhigh | Codex Security · GPT-5.6 Sol | 77 | 4 | 43 | 365 |
| Codex Security · GPT-5.6 Luna | Codex Security · GPT-5.6 Sol | 55 | 10 | 21 | 483 |
| Codex Security · GPT-5.6 Luna | Codex Security · GPT-5.6 Terra | 54 | 9 | 19 | 437 |
| Codex Security · GPT-5.6 Terra | Codex Security · GPT-5.6 Sol | 41 | 6 | 7 | 488 |
An empty cell means not applicable or unavailable as stated in `columns`; it never means zero.
View exact values
| Combination | Vulnerabilities |
|---|---|
| Snyk Code; Claude Code /security-review · Opus 5 xhigh; Claude Code /security-review · Opus 5 medium + Snyk MCP; Claude Code /security-review · Sonnet 5 xhigh; Codex Security (three configurations pooled) | 42 |
| Snyk Code; Claude Code /security-review · Opus 5 xhigh; Claude Code /security-review · Opus 5 medium + Snyk MCP; Claude Code /security-review · Sonnet 5 xhigh | 17 |
| Snyk Code | 10 |
| No endpoint-aware configuration | 7 |
| Claude Code /security-review · Opus 5 xhigh; Claude Code /security-review · Opus 5 medium + Snyk MCP; Claude Code /security-review · Sonnet 5 xhigh; Codex Security (three configurations pooled) | 7 |
| Snyk Code; Claude Code /security-review · Opus 5 xhigh; Claude Code /security-review · Opus 5 medium + Snyk MCP | 7 |
| Snyk Code; Codex Security (three configurations pooled) | 4 |
| Snyk Code; Claude Code /security-review · Opus 5 xhigh; Claude Code /security-review · Opus 5 medium + Snyk MCP; Codex Security (three configurations pooled) | 3 |
| Claude Code /security-review · Opus 5 xhigh; Claude Code /security-review · Opus 5 medium + Snyk MCP; Claude Code /security-review · Sonnet 5 xhigh | 2 |
| Snyk Code; Claude Code /security-review · Opus 5 xhigh | 2 |
| Claude Code /security-review · Opus 5 xhigh; Claude Code /security-review · Sonnet 5 xhigh | 1 |
| Claude Code /security-review · Opus 5 xhigh; Claude Code /security-review · Opus 5 medium + Snyk MCP | 1 |
| Claude Code /security-review · Opus 5 xhigh; Claude Code /security-review · Opus 5 medium + Snyk MCP; Codex Security (three configurations pooled) | 1 |
| Snyk Code; Claude Code /security-review · Sonnet 5 xhigh | 1 |
| Snyk Code; Claude Code /security-review · Sonnet 5 xhigh; Codex Security (three configurations pooled) | 1 |
| Snyk Code; Claude Code /security-review · Opus 5 xhigh; Claude Code /security-review · Sonnet 5 xhigh | 1 |
| Snyk Code; Claude Code /security-review · Opus 5 xhigh; Claude Code /security-review · Sonnet 5 xhigh; Codex Security (three configurations pooled) | 1 |
An empty cell means not applicable or unavailable as stated in `columns`; it never means zero.
Where each engine wins
Within one file and across files
Within a single file Snyk Code has the highest recall: 40 of the 46 same-file vulnerabilities, against 32 for Opus 5 xhigh. Across files the two are close: 49 of 62 and 53.
For the Claude Code configurations, the blind spots are about which classes they report, not about navigating a codebase.
One cell is hard for every engine: cross-file cross-site scripting, where no endpoint-aware configuration matched more than 4 of the 7. In 5 of those 7 the data flows from server-side code to a browser page; Snyk Code matched none of the 5 and Opus 5 xhigh 2.
Snyk Code's lower cross-file recall comes largely from this cell: with cross-site scripting removed, its cross-file and same-file recall are essentially equal (47 of 55 and 29 of 34).
View exact values
| Configuration | Same-file matched | Cross-file matched | Same-file misses | Misses in classes the built-in review policy excludes or restricts | Misses in cross-site scripting |
|---|---|---|---|---|---|
| Snyk Code | 40 of 46 | 49 of 62 | 6 | 1 | 1 |
| Claude Code /security-review · Opus 5 xhigh | 32 of 46 | 53 of 62 | 14 | 8 | 3 |
| Claude Code /security-review · Opus 5 medium + Snyk MCP | 30 of 46 | 50 of 62 | 16 | 9 | 3 |
| Claude Code /security-review · Sonnet 5 xhigh | 27 of 46 | 46 of 62 | 19 | 11 | 4 |
| Codex Security · GPT-5.6 Luna | 14 of 46 | 31 of 62 | 32 | 11 | 9 |
| Codex Security · GPT-5.6 Terra | 14 of 46 | 21 of 62 | 32 | 11 | 8 |
| Codex Security · GPT-5.6 Sol | 12 of 46 | 22 of 62 | 34 | 12 | 7 |
An empty cell means not applicable or unavailable as stated in `columns`; it never means zero.
The cost of combining
A larger queue to triage
Snyk Code and Opus 5 xhigh together report 539 findings for their 101 matches. 336 of Snyk Code's 425 findings matched no reference vulnerability; 87% of those are in classes outside the 14 scored classes, led by hardcoded credentials (195).
Counting only reports in the scored classes, precision is 69% (89 of 129) for Snyk Code against 81% (85 of 105) for Opus 5 xhigh.
View exact values
| Configuration | Findings | Matched | Precision against the reference set (lower bound) |
|---|---|---|---|
| Snyk Code | 425 | 89 | 20.9% |
| Claude Code /security-review · Opus 5 xhigh | 114 | 85 | 74.6% |
| Claude Code /security-review · Opus 5 medium + Snyk MCP | 97 | 80 | 82.5% |
| Claude Code /security-review · Sonnet 5 xhigh | 98 | 73 | 74.5% |
| Codex Security · GPT-5.6 Luna | 216 | 45 | 20.8% |
| Codex Security · GPT-5.6 Terra | 221 | 35 | 15.8% |
| Codex Security · GPT-5.6 Sol | 267 | 34 | 12.7% |
An empty cell means not applicable or unavailable as stated in `columns`; it never means zero.
Findings outside the reference set are not proven false; both precision measures are lower bounds.
Findings outside the reference set
Real vulnerabilities the answer key missed
23 clusters of findings outside the reference set were reported by at least three configurations from at least two tool families. We reviewed the 15 of them that Snyk Code did not report and that fall in a scored class or are CSRF: thirteen were real, one was borderline and one was judged to be by design; none was noise.
In this run, AI configurations found at least seven real vulnerabilities in scored classes that the reference set did not contain and Snyk Code did not report. All seven were reproduced live.
Codex Security configurations reported all seven, the Claude Code configurations six and DeepSec three; the consensus filter gives more weight to the family with three configurations, so these counts do not measure how broadly each family discovers issues.
They follow data where a first-party taint model typically ends: through library semantics and across the server-to-browser hop.
Each candidate had a code-level first pass and an independent skeptical second pass, both by AI agents, and a final call by an author; the consensus filter favors issues several tools can see. These findings are never added to the reference set or the recall results, and they are a lower-bound count, not a miss rate for any engine.
Harness policy
A built-in policy that suppresses real classes
The built-in /security-review prompt in Claude Code 2.1.251, the version that ran, excludes ReDoS and asks that prototype pollution and open redirect be reported only at extremely high confidence. These classes were chosen from the prompt text, before looking at results.
No Claude Code configuration reported a single ReDoS finding anywhere in the three applications that contain one. For the 11 open redirects, counting a finding of the class anywhere in the application, the Claude Code configurations reported 2 to 6 of the 11 and each Codex Security configuration reported 10 of the 11, though Codex Security was credited for only 4 or 5 of the 11 open redirects; Snyk Code reported and was credited for all 11.
Prototype pollution is weaker evidence: Opus 5 at both effort settings reported all 6 and was credited for 4.
Prompt-swap control (supplementary, 19 of the 20 applications, single run): matched 16 of the 20 vulnerabilities in the classes the policy excludes or restricts, against 9 with /security-review, with little change elsewhere.
View exact values
| Configuration | Classes the built-in review policy excludes or restricts | XSS in React/Angular applications | All other vulns |
|---|---|---|---|
| Snyk Code | 18 of 20 | 4 of 7 | 67 of 81 |
| Claude Code /security-review · Opus 5 xhigh | 9 of 20 | 5 of 7 | 71 of 81 |
| Claude Code /security-review · Opus 5 medium + Snyk MCP | 5 of 20 | 5 of 7 | 70 of 81 |
| Claude Code /security-review · Sonnet 5 xhigh | 6 of 20 | 4 of 7 | 63 of 81 |
| Codex Security · GPT-5.6 Luna | 6 of 20 | 3 of 7 | 36 of 81 |
| Codex Security · GPT-5.6 Terra | 5 of 20 | 1 of 7 | 29 of 81 |
| Codex Security · GPT-5.6 Sol | 4 of 20 | 1 of 7 | 29 of 81 |
An empty cell means not applicable or unavailable as stated in `columns`; it never means zero.
View exact values
| Configuration | Class | Credited | Reported anywhere in the application |
|---|---|---|---|
| Snyk Code | open redirect | 11 of 11 | 11 of 11 |
| Snyk Code | prototype pollution | 6 of 6 | 6 of 6 |
| Snyk Code | ReDoS | 1 of 3 | 2 of 3 |
| Claude Code /security-review · Opus 5 xhigh | open redirect | 5 of 11 | 6 of 11 |
| Claude Code /security-review · Opus 5 xhigh | prototype pollution | 4 of 6 | 6 of 6 |
| Claude Code /security-review · Opus 5 xhigh | ReDoS | 0 of 3 | 0 of 3 |
| Claude Code /security-review · Opus 5 medium + Snyk MCP | open redirect | 1 of 11 | 2 of 11 |
| Claude Code /security-review · Opus 5 medium + Snyk MCP | prototype pollution | 4 of 6 | 6 of 6 |
| Claude Code /security-review · Opus 5 medium + Snyk MCP | ReDoS | 0 of 3 | 0 of 3 |
| Claude Code /security-review · Sonnet 5 xhigh | open redirect | 4 of 11 | 5 of 11 |
| Claude Code /security-review · Sonnet 5 xhigh | prototype pollution | 2 of 6 | 3 of 6 |
| Claude Code /security-review · Sonnet 5 xhigh | ReDoS | 0 of 3 | 0 of 3 |
| Codex Security · GPT-5.6 Luna | open redirect | 5 of 11 | 10 of 11 |
| Codex Security · GPT-5.6 Luna | prototype pollution | 1 of 6 | 3 of 6 |
| Codex Security · GPT-5.6 Luna | ReDoS | 0 of 3 | 0 of 3 |
| Codex Security · GPT-5.6 Terra | open redirect | 5 of 11 | 10 of 11 |
| Codex Security · GPT-5.6 Terra | prototype pollution | 0 of 6 | 1 of 6 |
| Codex Security · GPT-5.6 Terra | ReDoS | 0 of 3 | 3 of 3 |
| Codex Security · GPT-5.6 Sol | open redirect | 4 of 11 | 10 of 11 |
| Codex Security · GPT-5.6 Sol | prototype pollution | 0 of 6 | 6 of 6 |
| Codex Security · GPT-5.6 Sol | ReDoS | 0 of 3 | 1 of 3 |
An empty cell means not applicable or unavailable as stated in `columns`; it never means zero.
View exact values
| Subset | Supplementary prompt-swap control (Opus 5 xhigh, default audit prompt) | Main run: Claude Code /security-review · Opus 5 xhigh, same applications |
|---|---|---|
| Classes the built-in review policy excludes or restricts | 16 of 20 | 9 of 20 |
| All other non-React/Angular | 71 of 78 | 69 of 78 |
| Open redirect | 9 of 11 | 5 of 11 |
| Prototype pollution | 5 of 6 | 4 of 6 |
| ReDoS | 2 of 3 | 0 of 3 |
An empty cell means not applicable or unavailable as stated in `columns`; it never means zero.
policy_control_supplementary.csvpolicy_control_supplementary.meta.json
The control is shown beside the main results and never merged into them; changes on the model provider's side cannot be excluded.
Localization
The right function, a line above the dangerous call
Codex Security with GPT-5.6 Sol located 80 of the 108 vulnerabilities at file level, but 34 under the two-line rule. When it missed a curated sink, its nearest reported location in the same file sat above the curated line in 39 of the 41 cases where that location was not itself a source, a median of six lines above.
A harness can detect a vulnerability and still hand the developer the wrong line. Line-level evidence is what makes a finding actionable.
View exact values
| Offset | Missed curated sinks | |
|---|---|---|
| Offset in lines | Reported location is a curated source | Reported location is not a curated source |
| ≤−21 | 0 | 1 |
| −20…−11 | 1 | 8 |
| −10…−6 | 9 | 15 |
| −5…−3 | 6 | 15 |
| ≥+3 | 0 | 2 |
Offset: Reported line minus curated sink line; negative = above the sink.
An empty cell means not applicable or unavailable as stated in `columns`; it never means zero.
View exact values
| Configuration | Line tolerance | |||||||
|---|---|---|---|---|---|---|---|---|
| Configuration | Exact line | ±1 lines | ±2 lines (used for results) | ±3 lines | ±5 lines | ±10 lines | ±20 lines | Any line in the right file |
| Snyk Code | 85 | 88 | 89 | 89 | 89 | 89 | 89 | 89 |
| Claude Code /security-review · Opus 5 xhigh | 79 | 84 | 85 | 86 | 86 | 86 | 86 | 89 |
| Claude Code /security-review · Opus 5 medium + Snyk MCP | 74 | 79 | 80 | 81 | 81 | 81 | 81 | 84 |
| Claude Code /security-review · Sonnet 5 xhigh | 55 | 71 | 73 | 75 | 75 | 76 | 77 | 76 |
| Codex Security · GPT-5.6 Luna | 15 | 32 | 45 | 50 | 55 | 61 | 64 | 66 |
| Codex Security · GPT-5.6 Terra | 6 | 20 | 35 | 39 | 47 | 63 | 66 | 69 |
| Codex Security · GPT-5.6 Sol | 2 | 18 | 34 | 43 | 54 | 71 | 77 | 80 |
An empty cell means not applicable or unavailable as stated in `columns`; it never means zero.
A pre-model ceiling
DeepSec's file selection fixes a recall ceiling before the model runs
DeepSec's model-free scan stage queued at least one file from the curated flow for only 56 of the 108 vulnerabilities: all 12 Java vulnerabilities and 23 of 30 in JavaScript and TypeScript, but 11 of 32 in Go and 10 of 34 in Python.
Conditional on selection, the Opus 5 backend's localized recall was 37 of 56 and the GPT-5.6 Sol backend's 1 of 56. The GPT-5.6 Sol backend exported no findings in 16 of its 20 runs; the records cannot tell the backend's behavior inside DeepSec from an integration problem, so this row describes the configuration as executed and says nothing about the model.
View exact values
| Stage | Vulnerabilities |
|---|---|
| Reference vulnerabilities | 108 |
| A flow file among the scan stage's candidates | 56 of 108 |
| The sink file among the candidates (vulnerabilities with a labeled sink) | 44 of 107 |
| Localized match, Opus 5 xhigh backend | 37 of 56 |
| Localized match, GPT-5.6 Sol backend | 1 of 56 |
Localized recall is DeepSec's primary metric and is not comparable with Attacker-Reachable Vulnerability Recall.
An empty cell means not applicable or unavailable as stated in `columns`; it never means zero.
View exact values
| Language family | Vulnerabilities |
|---|---|
| Go | 11 of 32 |
| JavaScript / TypeScript | 23 of 30 |
| Python | 10 of 34 |
| Java | 12 of 12 |
Localized recall is DeepSec's primary metric and is not comparable with Attacker-Reachable Vulnerability Recall.
Efficiency
What coverage costs
Per matched vulnerability, wall time was 5 seconds for Snyk Code and between 107 and 942 seconds for the endpoint-aware AI configurations.
Known cost per matched vulnerability ranged from $0.47 (Codex Security with GPT-5.6 Luna) to $21.92 (Codex Security with GPT-5.6 Sol). The recall-versus-cost frontier consists of Codex Security with GPT-5.6 Luna and the three Claude Code configurations.
Per matched vulnerability, the Claude Code configurations reported 1.21 to 1.34 findings, Snyk Code 4.78 and the Codex Security configurations 4.80 to 7.85: a measure of how much a team would review, not how much of it is noise.
The Snyk MCP configuration matched 80 vulnerabilities, every one of which Opus 5 xhigh also matched, at 0.35 times the cost. Effort, MCP access and the prompt all differ, so this is a cheaper configuration that kept 80 of the 85, not an effect of grounding.
View exact values
| Configuration | Wall time, total | Wall time per matched vulnerability (s) | Cost status | Known cost, total (USD) | Known cost per matched vulnerability (USD) | Tokens per matched vulnerability (millions) | Findings per matched vulnerability |
|---|---|---|---|---|---|---|---|
| Snyk Code | 8 min | 5 | no per-scan model cost | — | — | — | 4.78 |
| Claude Code /security-review · Opus 5 xhigh | 5.6 h | 236 | known | 164.53 | 1.94 | 1.03 | 1.34 |
| Claude Code /security-review · Opus 5 medium + Snyk MCP | 2.4 h | 107 | known | 57.44 | 0.72 | 0.35 | 1.21 |
| Claude Code /security-review · Sonnet 5 xhigh | 3.1 h | 153 | known | 39.56 | 0.54 | 0.72 | 1.34 |
| Codex Security · GPT-5.6 Luna | 5.4 h | 433 | known | 21.32 | 0.47 | 24.08 | 4.8 |
| Codex Security · GPT-5.6 Terra | 4.9 h | 508 | known | 207.99 | 5.94 | 24.42 | 6.31 |
| Codex Security · GPT-5.6 Sol | 8.9 h | 942 | known | 745.17 | 21.92 | 42.11 | 7.85 |
One run per configuration and application: every ratio is a single observation. Snyk Code has no per-scan model cost; its license cost is outside this study.
An empty cell means not applicable or unavailable as stated in `columns`; it never means zero.
View exact values
| Configuration | Wall time, total | Wall time per matched vulnerability (s) | Cost status | Known cost, total (USD) | Known cost per matched vulnerability (USD) | Tokens per matched vulnerability (millions) |
|---|---|---|---|---|---|---|
| DeepSec · Opus 5 xhigh | 17.8 h | 1733 | known | 355.17 | 9.60 | 3.69 |
| DeepSec · GPT-5.6 Sol xhigh | 3.3 h | 11752 | unavailable | — | — | 12.99 |
One run per configuration and application: every ratio is a single observation. Cost is known cost only ($1,594.08 across the main matrix); an unavailable cost is never shown as zero. Snyk Code has no per-scan model cost; its license cost is outside this study. Tokens compare only within a provider family.
Robustness
Which conclusions depend on the scoring rule
Rank agreement with the rule used for all results ranges from a Kendall τ of 1.00 down to 0.33; the top four change membership under 7 of the 20 alternatives.
Leaving out one application at a time changes some rank in 4 of the 20 cases and the top rank in none.
In two supplementary repetitions, Snyk Code returned byte-identical findings on all 20 applications, and the same 89 matches each time. The AI configurations ran once per application.
View exact values
| Scoring rule | Rank by macro recall | Agreement | ||||||
|---|---|---|---|---|---|---|---|---|
| Scoring rule | Snyk Code | Claude Code /security-review · Opus 5 xhigh | Claude Code /security-review · Opus 5 medium + Snyk MCP | Claude Code /security-review · Sonnet 5 xhigh | Codex Security · GPT-5.6 Luna | Codex Security · GPT-5.6 Terra | Codex Security · GPT-5.6 Sol | Kendall's τ |
| Endpoint rule, ±2 lines (used for all results) | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 1.00 |
| Endpoint rule, exact line | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 1.00 |
| Endpoint rule, ±1 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 1.00 |
| Endpoint rule, ±3 | 1 | 2 | 3 | 4 | 5 | 7 | 6 | 0.90 |
| Endpoint rule, ±5 | 1 | 2 | 3 | 4 | 6 | 7 | 5 | 0.81 |
| Endpoint rule, ±10 | 1 | 2 | 3 | 4 | 7 | 6 | 5 | 0.71 |
| Endpoint rule, ±20 | 1 | 2 | 3 | 5 | 7 | 6 | 4 | 0.62 |
| Endpoint rule, right file, any line | 2 | 1 | 3 | 5 | 7 | 6 | 4 | 0.52 |
| Source and sink both required, exact line | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 1.00 |
| Source and sink both required, ±2 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 1.00 |
| Sink required, ±2 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 1.00 |
| Source required, ±2 | 1 | 2 | 3 | 4 | 6 | 7 | 5 | 0.81 |
| Maximum matching instead of greedy | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 1.00 |
| No type aliases | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 1.00 |
| Many-to-one credit | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 1.00 |
| Any location, ±2 | 1 | 2 | 3 | 5 | 6 | 7 | 4 | 0.71 |
| Any location, exact line | 1 | 2 | 3 | 4 | 5 | 7 | 6 | 0.90 |
| Any location, ±5 | 1 | 2 | 3 | 5 | 7 | 6 | 4 | 0.62 |
| Any location, ±10 | 1 | 2 | 3 | 5 | 7 | 6 | 4 | 0.62 |
| Any location, right file, any line | 2 | 1 | 3 | 7 | 6 | 5 | 4 | 0.33 |
| Vulnerability type only | 1 | 2 | 4 | 7 | 6 | 5 | 3 | 0.33 |
Rank: Rank by macro recall under that rule (1 = highest). Kendall's τ: Rank agreement with the rule used for all results (first row).
An empty cell means not applicable or unavailable as stated in `columns`; it never means zero.
Operational meaning
Practical implications for security teams
- 01
Run deterministic SAST and AI review together
In this study neither was sufficient alone, and together they reached the ceiling of what all comparable configurations found, at the price of a larger triage queue. Deterministic SAST was measured on Snyk Code, the only SAST engine evaluated.
- 02
Read the harness as part of what you buy
A built-in policy, a localization habit or a pre-model file filter shapes what reaches the report.
- 03
Judge spend by coverage, not by price
A more expensive model did not reliably buy more coverage.
How 2.0 differs from JS 1.0
Two releases, two questions
VulnBench 2.0 takes the next steps JS 1.0 named: application-scale fixtures, an independent ground truth and stricter scoring. Its numbers are not comparable with JS 1.0's.
| Aspect | Snyk VulnBench JS 1.0 | Snyk VulnBench 2.0 |
|---|---|---|
| Question | Can LLMs find the same bugs twice? Repeatability and agreement. | What do AI security agents find that SAST does not, and what do they miss? |
| Fixtures | Ten small JavaScript and Express projects | 20 open-source web applications in Go, JavaScript/TypeScript, Python and Java |
| Reference set | Snyk Code's findings define the reference set | Curated, attacker-reachable vulnerabilities with annotated source-to-sink flows and author-verified exploits; not derived from any tool's findings |
| Matching | Same vulnerability type; file and line not required | Class plus source and sink, each within two lines; one finding credited to at most one vulnerability |
| Systems | Claude configurations through one agentic harness, plus Snyk Code reproducing its own reference | Productized harnesses: Snyk Code, Claude Code /security-review, Codex Security, DeepSec |
| Repetitions | Five identical runs per configuration and project | One run per configuration and application; Snyk Code repeated twice more in supplementary runs |
| Headline metric | Snyk-reference F1 and recurrence | Attacker-Reachable Vulnerability Recall (macro, with the matched count); DeepSec scored with localized recall |
Snyk Code's 100% in JS 1.0 is reproduction of the reference set it defined; in 2.0 Snyk Code is scored against an independent reference set like every other configuration. Never compare a 2.0 number with a JS 1.0 number.
Limitations
What the protocol cannot establish
- One run per configuration and application: run-to-run variation of the AI configurations is unmeasured, and every difference between them is a single observation.
- All authors are employees of Snyk, which develops Snyk Code. The Snyk Code product owner is a co-author, and his team shipped a rule update for one of the findings outside the reference set; all main results are reported as run, before that update.
- Reference vulnerabilities were partly seeded with OpenAI and Anthropic models, which could favor the AI configurations; some seeding prompts included vulnerable-pattern examples from a Snyk database, and five applications had been used in Snyk demonstrations, which could favor Snyk Code. The net effect is unknown.
- Without the five demonstration applications, Snyk Code matches 74 and Opus 5 xhigh 72 of the remaining 87 vulnerabilities, and they remain the top two.
- The reference set can omit real vulnerabilities; measured precision is a lower bound. One known defect makes one vulnerability unmatchable; correcting it raises Claude Code /security-review with Opus 5 medium + Snyk MCP from 80 to 81 and Opus 5 xhigh from 85 to 86, and the union of all seven to 102.
- The two-line tolerance, the endpoint rule and one-to-one credit are choices, not facts about the tools; the robustness section shows which conclusions depend on them.
- Snyk Code is the only SAST engine evaluated; statements about deterministic SAST are measured on Snyk Code and may not hold for other engines.
- Results belong to the configurations as run, including versions and modes; the design cannot separate harness from model.
- Cost, token and time figures come from single runs; unavailable costs are excluded, never treated as zero.
- Class names follow Snyk Code's vocabulary; findings labeled outside it could go uncredited. The measured effect is small: removing the reference set's alternative class names changes one match.
- The origin of each vulnerability, and which model seeded which application, were not recorded.
- The archive does not record the Snyk CLI version (the operator reported it after the run), and the Snyk MCP server ran unpinned, so its version is inferred; exact re-execution of those rows is bounded, re-scoring is not.
- Codex Security ran in its standard full-repository mode, not its deep mode, and its scans reported partial coverage on 7, 6 and 3 of the 20 applications for GPT-5.6 Luna, Terra and Sol; partial scans are scored as returned.
- Five failed attempts preceded the scored success in 4 of the 180 runs; only the final attempt is scored.
- Several applications are intentionally vulnerable demonstrations, many vulnerabilities were seeded, and Java is thin; how the results carry over to production code bases is untested.
Continue the research trail