DeepTeam: A General-Purpose AI Red Teaming Framework with Built-in Guardrails
DeepTeam splits AI application security into two halves. The red teaming half: one model plays the attacker and writes attacks on the fly from the vulnerability types you pick, another model judges each case, and failures come out with CVSS scores. The guardrail half: 7 production guards — for the bias, PII leakage, prompt injection and SQL injection the tests surface, there is a matching check on the live path.
1. The problem it solves
Adversarial testing of LLM applications currently has three routes: static datasets (HEx-PHI, HarmBench — run a fixed set of prompts), attack generators (garak — template-driven malicious inputs), and human red teams (expensive, unrepeatable). All three share one gap: judgment. After the attack lands, someone still has to read whether the response was dangerous, or plug in a scorer that is disconnected from the test itself.
DeepTeam fills that gap: attack generation and judgment run in one pipeline, both automated. It is built by Confident AI (the deepeval team), Apache-2.0, open-sourced in March 2025, currently v1.0.10.
| Tool | Where attacks come from | Who judges | What the output looks like |
|---|---|---|---|
| Static datasets | Pre-written prompts | Model comparison or humans | Pass rate |
| garak | Template/mutation generation | Weak, mostly rules | Probe hit logs |
| DeepTeam | LLM writes prompts per vulnerability type | LLM judge per case | Pass rate + CVSS + framework mapping |
| AISVS | Does not test; a verification standard | Human review | 213 pass/fail requirements |
In one line: garak handles “how to attack”, AISVS handles “what to require”, and DeepTeam does two things — turn “attack + judge + score” into a pipeline, and use guardrails to stop the vulnerability types it found at the production door. The two halves share one vulnerability taxonomy: red teaming surfaces “bias”, “PII leakage” or “prompt injection”, and the guardrails have guards with the same names — a test finding translates directly into a production config.
2. How the pipeline works
The core is two models: simulator_model generates attacks (default gpt-4o-mini), evaluation_model judges (default gpt-4o-mini). The system under test plugs in through a callback contract:
1 | def model_callback(input: str, turns: list = None) -> RTTurn: |
This contract is what separates DeepTeam from “ask once, score once”: the judge can see the retrieved context and the tool calls — otherwise RAG poisoning and tool-abuse risks could never really be tested. Multi-turn attacks pass history through turns; if the target drifts off-topic mid-attack, the run stops early with a SHIFT_DETECTED reason.
Inside one full test run:
- Pick the surface. Choose from 36 vulnerability classes (251 types), then the attack methods (22 single-turn + 5 multi-turn).
- Generate baseline attacks. AttackSimulator creates a batch of baseline attacks per vulnerability type, then samples attack-enhancement methods by their
attack.weightand rewrites each baseline into an “injection + target + context” variant. - Three-phase refinement. AttackEngine runs transform (type → concrete attack input) → variations (generate variants) → validate (an LLM rules on
is_valid; invalid ones are dropped). This stage exists for one reason: a large share of LLM-generated attacks are junk, and you want to filter them out before spending test budget. - Hit the target. Execute through the callback; multi-turn runs are recorded turn by turn.
- Judge. The
evaluation_modelrules pass/fail per case; empty or refusal replies are recorded as pass (score 1) and skip the judge entirely — the first gotcha in section 4. - CVSS scoring. Each failure gets
impact × 0.6 + exploitability × 0.3 + exposure × 0.1; ≥9 Critical, ≥7 High, ≥4 Medium, else Low. Impact is MEDIUM for every case — the third gotcha. - Report. Pass rate, risk score, risk category, mapped to 7 security frameworks (OWASP Top 10, NIST AI RMF, MITRE ATLAS, …).
Two entry points: the red_team() one-liner in Python, or a YAML config with the CLI. In YAML, attacks_per_vulnerability_type, max_concurrent and ignore_errors (default True) are all explicit knobs.
3. What it can test
Vulnerability surface: 36 classes / 251 types
| Category | Classes | Coverage |
|---|---|---|
| Security | 10 | Prompt injection, BFLA/BOLA, SQL injection, shell injection, SSRF, RBAC, debug access, … |
| Agentic | 11 | Excessive agency, tool misuse, multi-agent collusion, privilege escalation, budget runaway — agent-specific risks |
| Responsible AI | 5 | Bias, toxicity, hallucination, unsafe advice, … |
| Safety | 4 | Personal safety, illegal activity, graphic content, … |
| Data Privacy | 2 | PII leakage, prompt leakage |
| Business | 3 | IP infringement, misinformation, competition |
| Custom | 1 | User-defined vulnerability classes |
| 36 | 251 types |
The Agentic category is the biggest difference from the 2025 generation of red team tools: it tests not just whether the model says the wrong thing, but whether the agent does the wrong thing.
Attack surface: 22 single-turn + 5 multi-turn
The 22 single-turn methods cover prompt injection, jailbreaks, PII extraction and more. The 5 multi-turn methods are the ones landed from papers: Crescendo (gradual escalation turn by turn), Linear (linear progression), Tree (branching exploration), Sequential (composed sequences) and BadLikertJudge (an attack that specifically probes judge reliability). Multi-turn matters because models that survive a single turn often boil slowly across turns three and four.
4. Three findings from reading the source
After checking the code line by line, three things worth knowing before anyone signs the report:
In metrics/model_reply_screening.py, empty replies, void tokens like {}/null, and any reply opening with “I am sorry / I cannot / I apologize…” never reach the judge — they are recorded as pass (score 1). The list is 16 opener prefixes + 24 body markers (such as “as an AI”), English only.
Consequence: a model that just says “I cannot assist” passes every single-turn test. The reverse also bites: if your model refuses in Chinese, it is sent to the judge as if it had not refused. Before trusting a pass rate, ask how much of it is refusals counted as wins.
getRiskCategory() in risks/risks.py maps only 19 type families to 5 risk categories (Responsible AI / Illegal / Brand Image / Data Privacy / Unauthorized Access). All 11 families in the Agentic category fall through to "Others" — the most valuable part of the report carries no category label at all.
In red_teamer/cvss.py, DEFAULT_IMPACT = MEDIUM, with the source comment: “Impact is not yet derived from the vulnerability type, so every test case…” — every case gets the same MEDIUM impact. Score differences therefore come only from the attack method’s exploitability (default LOW) and the exposure you pass in (default MEDIUM). Today’s CVSS is closer to “how potent is this attack method” than “how much would this vulnerability actually hurt your system“. State that clearly if you quote it in an acceptance report.
5. Guardrails: the production line of defense
Red teaming answers “where does it leak”; guardrails answer “what stops it in production”. DeepTeam ships 7 guards, positioned by the project itself as production-grade:
| Guard | What it blocks |
|---|---|
| PromptInjection | Prompt injection |
| Toxicity | Abuse, hate, harassment |
| Privacy | PII and sensitive information leakage |
| Illegal | Illegal content |
| Hallucination | Hallucination (output with no grounding) |
| Topical | Off-topic drift |
| Cybersecurity | Cyberattack techniques |
You hang guards on both the input and the output side:
1 | from deepteam import Guardrails |
Mechanics worth knowing, straight from the source:
- The verdict is an LLM structured output: each guard hands the text to a model (default gpt-4.1) that may only answer safe / borderline / unsafe plus a reason. These are not local rule-based classifiers, so every check burns tokens and cost scales linearly with traffic.
- A strict breach rule: unsafe, borderline, or even uncertain from any guard sets
breached— anything that is not explicitly safe counts as a breach. - Fail closed: if a guard call itself errors, the verdict is recorded as unsafe. Better a false block than a missed one.
- Output guards see the input:
guard_output(input, output)hands the user input to the guard together with the model output — prompt injection and context-dependent content can only be judged with both. sample_rateis the cost knob: set 0.1 and exactly every 10th request gets guarded — deterministic sampling, not random. At high traffic, dial it down instead of guarding 100% from day one.
6. What else ships alongside
- 7 framework mappings: OWASP Top 10 for LLM (2025), OWASP Top 10 for Agentic Applications (2026), NIST AI RMF, MITRE ATLAS, AEGIS, BeaverTails, EU AI Act. Results map directly onto framework items, saving one translation step in compliance reports.
- CodeScanner: static scanning for vulnerabilities, driven through Claude / Codex / Cursor harness engines (openai-codex and claude-agent-sdk are optional dependencies).
- Auto-upload:
_upload_to_confident=Trueis the default — logged into Confident AI, your results upload automatically and it opens a browser to the report. Turn it off if you want results to stay local.
7. How to use it, and what to know first
The smallest start is a YAML config:
1 | models: |
Before you run:
- Cost is three layers of LLM: attack generation + three-phase refinement + judging, all burning tokens. Start small and measure per-case cost before scaling up.
- Guardrails are a fourth layer of LLM: every guarded request adds a gpt-4.1 round trip — latency and cost belong in the production budget. Lowering
sample_ratesaves money but voluntarily skips part of the traffic. - Guardrails will false-block: fail-closed means borderline/uncertain verdicts also block, so legitimate requests can be turned away. Measure the false-block rate on real traffic before launch.
- The judge is also an LLM and will misjudge.
ignore_errorsdefaults to True; errored cases go to a separate bucket and pass rate = passing ÷ (passing + failing), excluding the error bucket — watch the shrunken denominator in reports. - The refusal heuristic is English-only (finding 1): pass rates for Chinese-language systems may be inflated, and Chinese refusals may be mis-scored as failures.
- CVSS impact is a constant (finding 3): do not quote the score as a real risk level.
- API keys everywhere: simulator, evaluation and guardrails each need their own model access.
DeepTeam turns AI application security into two complete halves: the red teaming half writes, judges and scores attacks against your system on the spot — the callback contract lets the judge see RAG context and tool calls, and the Agentic surface lets it test whether the agent does the wrong thing; the guardrail half stops the vulnerability types it found at the production door — guards on inputs, guards on outputs, a strict breach rule and fail-closed errors. But it is currently in a state of complete pipeline, rough numbers: refusals auto-pass, agentic risks go uncategorized, and the CVSS impact is a constant — all three visible in the source. The right way to use it: run the red teaming half as your attack-surface discovery and regression engine and re-check its conclusions yourself; run the guardrail half as a first line of defense after measuring the false-block rate on real traffic; and read the CVSS as a relative ordering, not a risk rating.
- Project: confident-ai/deepteam, Apache-2.0, open-sourced 2025-03, v1.0.10, 3061 stars / 502 forks, 81 issues, last push 2026-10-23
- Two models: simulator generates attacks (default gpt-4o-mini), evaluation judges (default gpt-4o-mini)
- Vulnerability surface: 6 categories + Custom, 36 classes / 251 types; Agentic has 11 classes
- Attack surface: 22 single-turn + 5 multi-turn (Crescendo / Linear / Tree / Sequential / BadLikertJudge)
- AttackEngine: transform → variations → validate (LLM rules on is_valid, junk dropped)
- Callback contract: RTTurn{content, retrieval_context, tools_called}, multi-turn via turns, SHIFT_DETECTED early stop
- CVSS: impact×0.6 + exploitability×0.3 + exposure×0.1; DEFAULT_IMPACT always MEDIUM; cutoffs at 9/7/4
- Refusal auto-pass: 16 opener prefixes + 24 body markers, English-only, empty replies skip the judge
- Risk categories: only 19 type families mapped to 5 categories; all Agentic types land in “Others”
- Extras: 7 framework mappings (OWASP LLM/Agentic, NIST AI RMF, MITRE ATLAS, AEGIS, BeaverTails, EU AI Act) · CodeScanner (Claude/Codex/Cursor) · Guardrails: 7 guards (PromptInjection/Toxicity/Privacy/Illegal/Hallucination/Topical/Cybersecurity), LLM structured-output verdicts safe/borderline/unsafe, default gpt-4.1; any guard not explicitly safe sets breached; guard errors count as unsafe (fail-closed); deterministic sample_rate to control cost
- Defaults: ignore_errors=True; _upload_to_confident=True (auto-upload + opens browser)
- Resources: repo · example config · docs