How Deterministic SAST and AI Security Agents Divide the Work: Coverage, Harness Policy and Cost in Snyk VulnBench 2.0
Organizations: Snyk
Abstract
We ask what AI coding agents and AI security harnesses find that deterministic static application security testing (SAST) does not, and what they miss that SAST catches. VulnBench 2.0 is a benchmark of 108 hand-curated, attacker-reachable vulnerabilities in 20 open-source web applications in Go, JavaScript/TypeScript, Python and Java; 62 flow across more than one file. A finding is credited only if it locates the vulnerability's attacker-controlled source and its dangerous sink, each within two lines. We evaluate nine productized configurations under one blind protocol: the Snyk Code static analyzer, Claude Code's /security-review with three model and effort settings (one with the Snyk MCP server), Codex Security with GPT-5.6 Luna, Terra and Sol, and the DeepSec scanner with two model backends. Snyk Code reached 82.4% macro recall (89 of 108) and Claude Code with Opus 5 at xhigh effort 79.3% (85 of 108); they disagree on 28 vulnerabilities, split 16 to 12, too few to tell them apart. Neither engine was sufficient alone: together they reached 101 of 108, the ceiling of all seven comparable configurations combined, and the AI configurations also reported at least seven real vulnerabilities that the reference set did not contain and Snyk Code did not report. What an AI engine misses depends on its harness as much as on its model: without Claude Code's built-in review policy, the same model matched 16 instead of 9 of the 20 vulnerabilities in the classes that policy excludes or restricts (supplementary run on 19 of 20 applications); Codex Security with GPT-5.6 Sol located 80 vulnerabilities at file level but 34 at line level; DeepSec's model-free file selection kept a file from only 56 of the 108 flows. Coverage and cost were only loosely related. The harness, fixtures, reference sets and all run data are public.
Figures & tables
| Language family | Applications | Vulnerabilities | Cross-file | Same-file |
|---|---|---|---|---|
| Go | 6 | 32 | 25 | 7 |
| JavaScript / TypeScript | 7 | 30 | 10 | 20 |
| Python | 5 | 34 | 21 | 13 |
| Java | 2 | 12 | 6 | 6 |
| Total | 20 | 108 | 62 | 46 |
| Harness | Model | Effort, budget | Prompt | Primary metric |
|---|---|---|---|---|
| Snyk Code CLI 1.1305.1 c | — | — | none | AR recall |
| Claude Code 2.1.251 b /security-review | Opus 5 | xhigh, 30 turns | benchmark system prompt + /security-review | AR recall |
| Claude Code 2.1.251 b /security-review | Sonnet 5 | xhigh, 30 turns | as above | AR recall |
| Claude Code 2.1.251 b /security-review + Snyk MCP ( snyk@latest , 1.1307.0 d ) | Opus 5 | medium, 30 turns | as above + one required snyk_code_scan | AR recall |
| Codex Security 0.1.24 a (plugin 0.1.79 a ) | GPT-5.6 Luna | xhigh, standard scan | built-in | AR recall |
| Codex Security 0.1.24 a | GPT-5.6 Terra | xhigh, standard scan | built-in | AR recall |
| Configuration | Primary ( 2 lines) | Exact line |
|---|---|---|
| Snyk Code | 89 | 85 |
| Claude Code /security-review , Opus 5 xhigh | 85 | 79 |
| Claude Code /security-review , Opus 5 medium + Snyk MCP | 80 | 74 |
| Claude Code /security-review , Sonnet 5 xhigh | 73 | 55 |
| Codex Security, GPT-5.6 Luna | 45 | 15 |
| Codex Security, GPT-5.6 Terra | 35 | 6 |
| Configuration | Macro recall | Matched | 95% interval | Precision |
|---|---|---|---|---|
| Attacker-Reachable Vulnerability Recall | ||||
| Snyk Code | 82.4% | 89 of 108 | 74.0–90.5 | 20.9% (89/425) |
| Claude Code, Opus 5 xhigh | 79.3% | 85 of 108 | 71.6–86.7 | 74.6% (85/114) |
| Claude Code, Opus 5 medium + Snyk MCP | 75.2% | 80 of 108 | 68.2–82.3 | 82.5% (80/97) |
| Claude Code, Sonnet 5 xhigh | 67.0% | 73 of 108 | 57.7–76.2 | 74.5% (73/98) |
| Codex Security, GPT-5.6 Luna | 41.2% | 45 of 108 | 26.6–56.5 | 20.8% (45/216) |
Appendix figures & tables12 assets
Supplementary material from the paper’s appendix.
Appendix
| Fixture | Family | Frameworks | Vulns | Cross | Same | Svc | Src/snk | Locs | Per vuln |
|---|---|---|---|---|---|---|---|---|---|
| ardanservice | Go | chi, sqlx, goth | 5 | 5 | 0 | 0 | 5/5 | 23 | 4.6 |
| blanq | JS/TS | nuxt, vue, drizzle | 7 | 0 | 7 | 2 | 7/7 | 19 | 2.7 |
| boilwater | JS/TS | express | 4 | 3 | 1 | 0 | 3/4 | 13 | 3.2 |
| coffeeshop | Java | spring-boot, thymeleaf, spring-security | 5 | 2 | 3 | 0 | 6/5 | 15 | 3.0 |
| conduit | Python | flask | 6 | 4 | 2 | 0 | 10/6 | 26 | 4.3 |
| flask-bones | Python | flask | 10 | 4 | 6 | 0 | 10/10 | 31 | 3.1 |
| Configuration | Model | Parameters |
|---|---|---|
| Snyk Code | — | snyk code test <fixture> --json |
| Claude Code /security-review | claude-opus-5 | effort xhigh; 30 turns |
| Claude Code /security-review | claude-sonnet-5 | effort xhigh; 30 turns |
| Claude Code /security-review + Snyk MCP | claude-opus-5 | effort medium; 30 turns; one required snyk_code_scan |
| Codex Security | gpt-5.6-luna , gpt-5.6-terra , gpt-5.6-sol | effort xhigh; standard mode |
| DeepSec | claude-opus-5 , gpt-5.6-sol | reasoning xhigh; 150 turns per batch; batch size 5; concurrency 1 |
| Application | Class | Source sink | Boundary crossed | Reported by |
|---|---|---|---|---|
| sassyreg | XSS | registry response field authorName ( PackageProfile.js:134 ) innerHTML in PropsPoints.js:13 | server/stored data browser DOM | 7 (CC 3, CxS 3, DS 1) |
| halloween | Prototype pollution | JSON body of PUT /users/:id/settings/notifications ( userController.ts:78 ) two-level computed property write ( userService.ts:141 ) | through third-party code | 6 (CC 3, CxS 3) |
| saas-starter-kit | SQL injection | order query parameter ( handlers/user.go:69 ) go-sqlbuilder OrderBy ( internal/user/user.go:189 ) | through third-party code | 5 (CC 1, CxS 3, DS 1) |
| coffeeshop | Mass assignment | POST /profile form fields bound to the Person entity ( ProfileController.java:33 ) personRepository.save ( PersonService.java:44 ) | through third-party code | 5 (CC 3, CxS 2) |
| flask-bones | XSS | username at registration ( auth/views.py:73 ) Bootbox dialog message rendered as HTML ( application.js:10 ) | server/stored data browser DOM; through third-party code | 4 (CC 1, CxS 3) |
| iguana | XSS | project name set through the project create and edit forms ( project/forms.py:63,79 ; Project.name , project/models.py:61 ) jQuery .append in draw_activity_heatmap.js:129 (reproduced live); a d3 tooltip leg in draw_last_seven.js was also reported but not reproduced | server/stored data browser DOM; through third-party code | 4 (CxS 3, DS 1) |
Software Vulnerability Detection
Software vulnerability detection identifies insecure code, pinpoints weaknesses, and helps developers validate or prevent exploitable bugs.
See all 146 papers