Skip to main content

Quality-diversity evolutionary red-teaming for LLMs and agents - single-turn, multi-turn, and agentic/MCP attacks

Project description

rotalabs-redqueen

Quality-diversity evolutionary red-teaming for LLMs and agents, from Rotalabs.

Rather than hand-crafting jailbreaks, rotalabs-redqueen evolves diverse, effective attack strategies and maps the vulnerability space with MAP-Elites. It operates at the semantic level and spans the full 2026 attack surface:

  • Single-turn prompt attacks (strategies, encodings, personas)
  • Multi-turn Crescendo-style escalation
  • Agentic / tool-use / MCP multi-step exploit plans

Seeded runs are bit-reproducible (and cross-language portable), and a campaign can be projected into an audit-ready compliance report (OWASP, MITRE ATLAS, EU AI Act Art. 55, NIST AI RMF).

2.0 is a breaking release. See CHANGELOG.md for migration from 1.x.

Installation

pip install rotalabs-redqueen           # core + mock target
pip install rotalabs-redqueen[openai]   # + OpenAI
pip install rotalabs-redqueen[anthropic]
pip install rotalabs-redqueen[llm]      # all providers
pip install rotalabs-redqueen[dev]      # tests/lint

Quick start

import asyncio
from rotalabs_redqueen import (
    LLMAttackGenome, JailbreakFitness, MockTarget, HeuristicJudge, evolve,
)

async def main():
    target = MockTarget()  # swap for OpenAITarget / AnthropicTarget / GeminiTarget / OllamaTarget
    fitness = JailbreakFitness(target, HeuristicJudge())

    result = await evolve(
        genome_class=LLMAttackGenome,
        fitness=fitness,
        generations=50,
        population_size=20,
        seed=1234,            # same seed -> same result, every time
        progress=False,
    )

    if result.best:
        print("fitness:", result.best.fitness.value)
        print("prompt:", result.best.genome.to_prompt())

asyncio.run(main())

Multi-turn and agentic attacks

The genome's phenotype is a Stimulus — a single prompt, a conversation, or an agentic action plan — so the same engine drives every surface. Just swap the genome class:

from rotalabs_redqueen import MultiTurnGenome, AgenticGenome, JailbreakFitness, MockTarget, evolve

# Crescendo-style multi-turn escalation
mt = await evolve(genome_class=MultiTurnGenome,
                  fitness=JailbreakFitness(MockTarget()),
                  generations=50, population_size=20, seed=1, progress=False)

# Multi-step tool-use / MCP exploit plans
ag = await evolve(genome_class=AgenticGenome,
                  fitness=JailbreakFitness(MockTarget()),
                  generations=50, population_size=20, seed=1, progress=False)

To drive a real MCP server instead of the deterministic MockTarget, use MCPTarget — it performs the MCP handshake and executes each agentic step as a tools/call, surfacing tool output for judging:

from rotalabs_redqueen.llm import MCPTarget

target = MCPTarget(command=["npx", "-y", "@modelcontextprotocol/server-everything"])
# agentic action-plan steps become MCP tool calls; the tool output is what the judge scores

Quality-diversity with MAP-Elites

from rotalabs_redqueen import (
    LLMAttackGenome, JailbreakFitness, MockTarget,
    MapElitesArchive, BehaviorDimension, AttackStrategy, Encoding, evolve,
)

archive = MapElitesArchive(dimensions=[
    BehaviorDimension("strategy", 0.0, 1.0, len(AttackStrategy)),
    BehaviorDimension("encoding", 0.0, 1.0, len(Encoding)),
    BehaviorDimension("has_persona", 0.0, 1.0, 2),
])
result = await evolve(genome_class=LLMAttackGenome,
                      fitness=JailbreakFitness(MockTarget()),
                      generations=100, archive=archive, seed=1, progress=False)

cov = result.archive.coverage()
print(f"coverage: {cov.coverage_percent:.1f}% ({cov.filled_cells} diverse attacks)")

Compliance report

Project the archive over the attack taxonomy into standards-aligned evidence:

from rotalabs_redqueen import ReportExporter

exporter = ReportExporter()
report = exporter.export(result.archive.get_all(),
                         campaign_id="run-1",
                         coverage=result.archive.coverage())
print(exporter.render(report, "markdown").decode())   # or "json"

The report groups successful attacks by harm category and crosswalks them to OWASP LLM/Agentic Top-10, MITRE ATLAS, EU AI Act Article 55, and NIST AI RMF GOVERN 1.7.

Co-evolution (attacker vs defender)

Evolve an attacker population against a defender population — defenders evolve guardrails that reduce attack success, attackers adapt to bypass them:

from rotalabs_redqueen import (
    coevolve, LLMAttackGenome, SystemPromptDefense,
    JailbreakFitness, DefenderBlockFitness, MockTarget, HeuristicJudge,
)

base, judge = MockTarget(), HeuristicJudge()
result = await coevolve(
    attacker_class=LLMAttackGenome,
    defender_class=SystemPromptDefense,
    attacker_fitness_vs=lambda d: JailbreakFitness(d.as_defense(base), judge),
    defender_fitness_vs=lambda a: DefenderBlockFitness(a, base, judge),
    generations=20, population_size=24, seed=1,
)
print(result.best_defender.to_dict(), result.attacker_fitness, result.defender_fitness)

Persistence and continuous red-teaming

Archives serialize, so attacks accumulate across runs (e.g. a CI gate that gets stronger over time):

from rotalabs_redqueen import MapElitesArchive, LLMAttackGenome, Rng

result.archive.save("file://archive.json")

prior = MapElitesArchive.load("file://archive.json", LLMAttackGenome)
warm_start = prior.seed(10, Rng(0))   # sample elite genomes to seed the next run

Command line

rotalabs-redqueen run --target mock:random --generations 20 --seed 1
rotalabs-redqueen run --target openai:gpt-4 --use-archive --output results.json
rotalabs-redqueen run --target mock:random --llm-judge anthropic:claude-sonnet-4-20250514
rotalabs-redqueen info --strategies | --encodings | --targets

Architecture

Core framework (generic, reusable for any QD problem): Genome, Fitness, Population, Selection (tournament / novelty / lexicase), MapElitesArchive, Evolution, and the canonical Rng.

LLM domain: LLMAttackGenome / MultiTurnGenome / AgenticGenome; targets — OpenAI, Anthropic, Gemini, Ollama, Mock, and MCPTarget (drives a real MCP server over stdio); Judge (heuristic, LLM); JailbreakFitness / MultiTargetFitness; co-evolution (coevolve, SystemPromptDefense, DefenderBlockFitness).

Surface Genome Stimulus kind
Single-turn LLMAttackGenome single_turn
Multi-turn MultiTurnGenome multi_turn
Agentic / MCP AgenticGenome agentic

Extending

Custom genome

from rotalabs_redqueen import Genome, BehaviorDescriptor, Stimulus

class MyGenome(Genome["MyGenome"]):
    @classmethod
    def random(cls, rng): ...
    def mutate(self, rng): ...
    def crossover(self, other, rng): ...
    def to_stimulus(self) -> Stimulus:
        return Stimulus.single_turn(prompt="...")
    def behavior(self) -> BehaviorDescriptor: ...
    def distance(self, other) -> float: ...
    def to_dict(self) -> dict: ...
    @classmethod
    def from_dict(cls, data) -> "MyGenome": ...

rng is the canonical Rng — use rng.random(), rng.integers(n), rng.choice(n, size, replace=False), rng.shuffle(list) so runs stay reproducible.

Custom target

from rotalabs_redqueen import LLMTarget, Message, TargetResponse

class MyTarget(LLMTarget):
    @property
    def name(self) -> str:
        return "my-target"

    async def _complete(self, messages: list[Message]) -> TargetResponse:
        text = await my_llm_api([{"role": m.role, "content": m.content} for m in messages])
        return TargetResponse(content=text, model="my-model")

interact() (single-turn + scripted multi-turn rollout) is provided by the base class.

Custom judge

from rotalabs_redqueen import Judge, JudgeResult

class MyJudge(Judge):
    async def judge(self, stimulus, transcript) -> JudgeResult:
        score = my_score(transcript.assistant_text)
        return JudgeResult(success=score >= 0.5, score=score)

Reproducibility & conformance

Seeded campaigns are deterministic and cross-language portable: the canonical PRNG (xoshiro256++ + SplitMix64) is cross-validated against an independent implementation, and an L1–L5 conformance suite gates engine, LLM-domain, report, multi-turn/agentic, and co-evolution behavior against golden fixtures, all reproduced byte-for-byte by the TypeScript package.

pytest                                            # full suite incl. conformance
python -m rotalabs_redqueen._gen_conformance      # regenerate golden fixtures (intentional changes only)

Use cases

Red-teaming, guardrail/defense testing, robustness benchmarking, and documented adversarial-testing evidence for compliance.

Responsible use

For defensive security research — testing systems you own or are authorized to test. Do not use it to attack systems without authorization or to circumvent the safety of production systems.

Links

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rotalabs_redqueen-2.0.0.tar.gz (206.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rotalabs_redqueen-2.0.0-py3-none-any.whl (66.9 kB view details)

Uploaded Python 3

File details

Details for the file rotalabs_redqueen-2.0.0.tar.gz.

File metadata

  • Download URL: rotalabs_redqueen-2.0.0.tar.gz
  • Upload date:
  • Size: 206.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.6

File hashes

Hashes for rotalabs_redqueen-2.0.0.tar.gz
Algorithm Hash digest
SHA256 a041891a5d07f1a9f518de71b21352869c094b323af867b4114179c9715514b5
MD5 1f51d22d9fbacd5840865a5133b85214
BLAKE2b-256 2b218200d735a4ee01cdda080cb8a1e1efabe79a7eb1b96a3229e12884dbc9b1

See more details on using hashes here.

File details

Details for the file rotalabs_redqueen-2.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for rotalabs_redqueen-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 49b70f638cd24dada337928a72d330d04e881c3929995f492f2919a9dc78cb61
MD5 bb9983c0c0fd0f289d330181b3426e85
BLAKE2b-256 6fe7551e1356218df3977fad3a82d22edd306df9fdbb5c8707867353247adb65

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page