How do you measure the success with which different agents perform regular, real-world cybersecurity tasks?
Many companies already use agents within their development and deployment ecosystem, and attackers sometimes use swarms of offensive agents to attack thousands of companies at once. To help defenders prepare for this new era, we need a score that compares what these agents can do. Because of how important this is, labs in academia across the industry are starting to work on measuring it and setting a standard for how to do it correctly, so the topic is timely and increasingly relevant.
In this post I’ll share the key principles Wiz followed to tackle this benchmarking imperative in the relaunch of our Cyber Model Arena. The full methodology, how we graded, and gathered our tasks is available for download. As of the writing of this blog, the Wiz Cyber Model Arena v3.9 consists of 26 models, four general-purpose harnesses, 59 agents, 327 challenges, three attempts per challenge, and 1,000 seconds each (these numbers are constantly growing).
To create a benchmark, fix the benchmark objective first. Then build the tasks, environment, and the measurement around it. I’ll get into this and explain the principles that guide the process, in greater detail later in this post.
Key Takeaways
Choose the right tasks. Settle the why (objective), the what (data, ground truth and agent setup) and the how (metrics, evaluation function) before you write the first task. Build the data from the real distribution where you can, not from AI-generated or AI-labeled tasks.
Grade with code, not LLMs. Measure success directly and deterministically, and apply anti-cheat measures: isolate the agent from the server and the internet, and give it no way to look up answers. Do not rely on an LLM-as-a-judge unless it is well designed, calibrated and free of bias.
Optimize evaluation for realism. Evaluate the harness and model together, give the agent more than one try, and weigh success against what a solve costs.
Avoid common pitfalls. LLM judges, small samples, task imbalance, model-only evaluation and answer leakage each make a benchmark unreliable. And start small: one harness, a quick and cheap model, a few tasks and a simple grader. Scale only after it works.
Start with a problem statement
Most public cyber-agent benchmarks answer a different question than the one a defender is asking. A multiple-choice quiz benchmark measures model knowledge not production performance, and an LLM output judged by another model measures agreement between the two, not success. We aim to answer whether the agent can perform a real attack.
Write down the one question your benchmark must answer, and test every later decision against it. Ours:
Given only the task instruction, a general-purpose agent scaffold, a 1,000-second budget, and no external knowledge sources, does the agent produce a checkable effect on a real target?
Wiz Research's 2026 State of AI in the Cloud Report found that at least 57% of organizations have deployed self-hosted AI agent technology, and that MCP servers appear in at least 80% of observed cloud environments. People are already buying and defending against these systems. That is the why. The rest of this post is how to build a number that serves it.
Design your benchmark
Define three things before you create your first challenge.
Why. A defender or a buyer should be able to act on the number. "Higher pass@1" is not a why. "Can this agent, as shipped, exploit a live target from the instruction alone?" is.
What. Name the subject under evaluation. Here it is an agent (model + harness + tools + system prompt) run by an attacker, which is why we use realistic limits: 1,000 seconds, three attempts, a simple system prompt, and access to client-side code but not server-side code.
How. It’s important for the benchmark to report a single bottom line metric per example. To reduce many competing metrics to a single number, pick one optimizing metric and treat everything else as a satisficing constraint. If you have five competing metrics and no way to reduce them, which agent is better becomes a debate over the metrics.
Make the tasks match the job
A benchmark can only speak for the tasks it contains. Sample only the hard tasks and you are no longer measuring success on the job, you are measuring success on hard tasks. And a benchmark that claims to measure "offensive capability" from a single task category oversells itself.
So we built four categories of equal weight from sources that already exist in the wild. We did not generate or label tasks with an LLM.
| Category | Tasks | What it tests |
|---|---|---|
| Code vulnerabilities | 221 | Finding known vulnerabilities in stripped open-source packages, or exploiting a live 1-day CVE |
| API security | 54 | Attacking black-box APIs with no source code |
| Web security | 29 | Exploiting real PHP web apps with the client source visible |
| Cloud security | 23 | Exploiting misconfigurations across AWS, Azure, GCP and Kubernetes-style setups |
The agents behave very differently from one category to the next. Averaged over the 59 agents, pass@1 is 78.0% on API security, 64.6% on web, 56.5% on cloud and 38.2% on code vulnerabilities. The top overall agent scores 74.7% on web and 65.8% on code (while web tops out at 90.8%). Another agent scores 9.7% on code and still 71.6% on API.
Size matters too. Many recent cybersecurity benchmarks have fewer than 30 tasks. At a 50% success rate, 30 tasks give a 95% confidence interval of roughly ±18 points, so an agent that scores 15 points higher than another is not necessarily better.
Grade an effect, not with LLMs
Ground truth is the foundation of evaluation. It has been standard practice to grade with an LLM-as-a-Judge, but judges do not directly measure success. They are biased (they often prefer the first option), random (they give different results each run), expensive, and slow, and they must be calibrated and de-biased before you can use them in a long-lived benchmark. When you use a judge, you measure whether an LLM thinks the agent succeeded. That difference is a debt baked into the system.
We use code instead. Every challenge is designed to leave a checkable effect behind or report precise structured outputs, and a deterministic grader inspects it after the agent is gone. Code graders are cheap, re-runnable, and not a model you have to calibrate.
Anti-cheating via isolation
Agents will shortcut a task when they can. They look the answer up online, read a solution off disk, or manipulate the grader. A score collected with web search, a CVE database or the challenge name in the folder measures something else: success at the task or success at breaking it. CTFusion moved their solve rate by as much as 12 points just by raising web-search access.
As for contamination, we cannot prove our agents never saw a task in pretraining. We can prove they cannot fetch one during the trial. Anti-cheat belongs in the environment, not in the prompt.
Start small
Building a benchmark is a nontrivial, evolving effort, and it is tempting to write 300 challenges before anything runs end to end. We apply lean-startup rules instead: get a small end-to-end baseline you can inspect by hand, then iterate.
You need ten tasks you can re-run, one harness you can deploy, and an evaluation metric a grader can check. After you’re convinced it works, you can scale it up.
What we found
Pair the harness with the model
A model on its own is a text predictor. It becomes an attacker inside a harness that runs commands and applies tools, and models do better or worse in different harnesses. Across the 22 models we ran on both Claude Code and ADK React, the mean absolute gap was 5.1 pass@1 points. Claude models prefer Claude Code, and Gemini 3.8 Flash Cyber prefers the thinner ADK loop.
The conclusion: test the system as a whole. Either pair the harness to the model (and as we’ve seen it’s best to match the harness to the model's creator), or fix one general harness and compare models inside it.
Attackers get more than one try
A real attacker does not stop after one failure. We gave every agent three attempts per challenge, and the extra attempts did more than lift scores. For some agents they even changed which one comes out ahead.
Accuracy has a price
Give an agent more time and money and it will usually solve more. So the useful chart plots success against what a solve costs. Any agent off the Pareto frontier is strictly worse than one on it. For example, Claude Code with GPT-5.6 Sol averages 64.2% pass@1 at $8.29 and 27.2 minutes per solve, however the Pareto frontier Codex + GPT-6 Luna is strictly better, averaging 64.5% pass@1 at only $0.05 and 6.3 minutes per solve.
Keep a short list of agents on the frontier and ignore the rest. That lets you ask "for this budget, how do I maximize success?" or "for this success rate, how do I minimize cost?"
Limitations
Four simple harnesses. A cyber-specialized harness would likely score higher, but we chose to measure a simple attacker.
String equality on code vulnerabilities. A semantically correct root cause that misses the expected symbol scores 0. We chose precision over recall.
Public web tasks. websec.fr is a known corpus. Isolation stops the agent from looking up the answer, not from remembering it from training (possibly resulting in benchmark contamination).
A time cap. 1,000 seconds is enough for most successful attacks we observed. In the future we think it is better to limit cost than time.
Confidence intervals. We have yet to publish them on the website, and we are working on it.
Conclusion
Our Cyber Model Arena shows how different agents perform on common cybersecurity tasks, across 327 isolated challenges in four categories. To build an agentic cybersecurity benchmark, fix the why, the what and the how first, and define the agent, the task mix, the grader, the isolation, the budget and the attempts. Get one wrong and the benchmark becomes garbage in, garbage out.
Appendix: Results for All 59 Agents
Every agent, ordered by pass@1. Scores are percentages.
Source: Wiz Cyber Model Arena v3.9.
| Harness | Model | pass@1 | pass@2 | pass@3 | $/solve @1 | min/solve @1 |
|---|---|---|---|---|---|---|
| ADK React | Gemini 4 Argon | 77.2 | 84.1 | 86.3 | 0.77 | 4.3 |
| Antigravity | Gemini 4 Argon | 77.0 | 85.1 | 87.5 | 0.97 | 8.4 |
| ADK React | Gemini 3.8 Flash Cyber | 74.9 | 79.7 | 81.5 | 1.62 | 5.0 |
| Claude Code | Claude Opus 5 | 71.2 | 77.4 | 79.4 | 2.63 | 12.2 |
| Codex | GPT-6 Sol | 71.2 | 75.4 | 77.0 | 0.67 | 6.6 |
| Claude Code | Gemini 4 Argon | 70.8 | 80.7 | 85.7 | 0.84 | 5.3 |
| Claude Code | GPT-6.1 Sol | 70.7 | 77.0 | 79.2 | 1.23 | 8.1 |
| Codex | GPT-6.1 Sol | 70.6 | 77.5 | 79.2 | 0.44 | 4.9 |
| Claude Code | GPT-6 Astra | 70.2 | 77.3 | 79.5 | 6.48 | 6.8 |
| Codex | GPT-5.6 Sol | 69.8 | 76.0 | 78.5 | 2.06 | 5.7 |
| Claude Code | GPT-6 Sol | 69.3 | 73.6 | 76.0 | 1.26 | 17.9 |
| Codex | GPT-6 Astra | 69.2 | 77.2 | 79.3 | 2.68 | 4.1 |
| Claude Code | Gemini 3.8 Flash Cyber | 68.5 | 75.3 | 78.0 | 1.52 | 5.7 |
| Antigravity | Gemini 3.8 Flash Cyber | 68.0 | 75.2 | 78.2 | 0.89 | 4.3 |
| ADK React | GPT-5.6 Sol | 66.9 | 71.0 | 72.0 | 7.46 | 15.3 |
| ADK React | Claude Sonnet 5.5 | 66.8 | 73.1 | 75.8 | 0.87 | 3.3 |
| Antigravity | Gemini 3.7 Flash | 65.6 | 71.8 | 74.0 | 0.47 | 7.0 |
| Claude Code | Claude Opus 4.8 | 65.4 | 70.3 | 71.8 | 2.77 | 11.9 |
| ADK React | Claude Opus 5.5 | 64.7 | 76.0 | 79.7 | 2.56 | 5.3 |
| Claude Code | Claude Sonnet 5.5 | 64.7 | 72.4 | 74.9 | 0.22 | 1.9 |
| Claude Code | Claude Opus 5.5 | 64.5 | 74.9 | 79.7 | 0.78 | 3.2 |
| Codex | GPT-6 Luna | 64.5 | 71.3 | 74.3 | 0.05 | 6.3 |
| Claude Code | GPT-5.6 Terra | 64.4 | 70.2 | 72.5 | 3.48 | 22.4 |
| Claude Code | GPT-5.6 Sol | 64.2 | 70.3 | 73.3 | 8.29 | 27.2 |
| Codex | GPT-5.6 Terra | 63.0 | 70.0 | 72.6 | 0.92 | 4.6 |
| ADK React | Gemini 3.6 Flash | 61.0 | 66.0 | 68.2 | 2.31 | 30.6 |
| ADK React | GPT-5.6 Terra | 60.9 | 68.1 | 70.6 | 4.16 | 15.7 |
| Claude Code | GPT-6 Luna | 60.5 | 66.3 | 69.3 | 0.09 | 21.1 |
| Claude Code | Gemini 3.5 Flash | 60.5 | 68.4 | 71.5 | 8.99 | 22.5 |
| Claude Code | DeepSeek V4.1 Flash 1017 | 60.3 | 68.2 | 72.0 | 0.17 | 24.4 |
| ADK React | Gemini 3.7 Flash | 59.7 | 64.8 | 67.2 | 0.95 | 38.7 |
| Antigravity | Gemini 3.6 Flash | 59.3 | 67.6 | 71.5 | 1.31 | 7.4 |
| Claude Code | Claude Sonnet 5 | 59.3 | 65.2 | 67.2 | 1.58 | 14.1 |
| Claude Code | Gemini 3.6 Flash | 59.1 | 66.2 | 69.0 | 9.32 | 16.0 |
| Claude Code | Gemini 3.7 Flash | 59.1 | 66.5 | 70.8 | 6.47 | 27.4 |
| ADK React | Claude Opus 5 | 58.7 | 62.8 | 64.7 | 2.37 | 26.3 |
| Claude Code | GLM-5.3 | 58.0 | 66.5 | 70.8 | 3.13 | 28.0 |
| ADK React | DeepSeek V4.1 Flash 1017 | 57.6 | 66.1 | 70.8 | 0.15 | 26.8 |
| Claude Code | Claude Haiku 5.5 | 57.0 | 67.0 | 71.0 | 0.22 | 6.6 |
| Claude Code | DeepSeek V4 Pro | 54.4 | 63.0 | 66.8 | 0.67 | 12.1 |
| ADK React | Gemini 3.5 Flash | 53.6 | 61.9 | 65.5 | 2.35 | 41.6 |
| ADK React | DeepSeek V4 Pro | 52.8 | 59.8 | 63.1 | 1.61 | 31.9 |
| ADK React | Claude Opus 4.8 | 52.5 | 58.1 | 59.8 | 1.53 | 19.2 |
| ADK React | Kimi K3 | 52.2 | 60.9 | 63.8 | 1.09 | 21.7 |
| Claude Code | Kimi K3 | 51.0 | 60.8 | 65.7 | 1.89 | 28.6 |
| Claude Code | Claude Sonnet 4.5 | 50.5 | 59.4 | 63.7 | 2.39 | 17.7 |
| Claude Code | DeepSeek V4.1 Flash | 50.2 | 57.0 | 61.0 | 0.41 | 39.4 |
| ADK React | GLM-5.3 | 49.1 | 56.1 | 60.8 | 1.40 | 40.1 |
| ADK React | Claude Haiku 5.5 | 48.6 | 56.2 | 58.5 | 0.05 | 7.1 |
| Claude Code | GLM 5.3 Flash | 48.2 | 56.6 | 60.4 | 0.34 | 33.9 |
| ADK React | DeepSeek V4.1 Flash | 47.4 | 55.6 | 59.1 | 0.22 | 40.1 |
| ADK React | Grok 4.6 | 46.6 | 62.1 | 67.5 | 2.39 | 43.0 |
| ADK React | Claude Sonnet 4.5 | 46.5 | 52.9 | 56.2 | 1.75 | 46.0 |
| Claude Code | Grok 4.6 | 45.5 | 55.5 | 58.7 | 2.85 | 51.2 |
| Antigravity | Gemini 3.5 Flash | 44.3 | 52.8 | 56.8 | 1.07 | 15.7 |
| ADK React | Claude Sonnet 5 | 42.0 | 47.5 | 50.5 | 1.69 | 42.5 |
| ADK React | GLM 5.3 Flash | 41.8 | 48.6 | 51.6 | 0.20 | 55.5 |
| ADK React | MiMo V2.6 Pro | 39.7 | 45.4 | 48.7 | 0.17 | 55.5 |
| Claude Code | MiMo V2.6 Pro | 39.0 | 44.4 | 47.5 | 0.53 | 58.7 |