Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Attack Techniques

An attack technique is anything that, once configured, generally helps an attack achieve its objective — a role-play framing, a many-shot priming set, a particular jailbreak template, a crescendo escalation. A technique is always specific to an attack: it is the how of one configured attack (the algorithm — e.g. RolePlayAttack, TreeOfAttacksWithPruningAttack), bundled with the seeds and configuration that make it a reusable recipe and packaged so a scenario can pick it by name. The objective — the what you are probing for — stays separate and is supplied by the dataset.

Technique vs. attack. The attack (a.k.a. executor) is the algorithm that runs prompts against a target. The technique wraps one configured attack so it can be registered, listed, tagged, and selected without the caller knowing how it is built. A Scenario runs a set of techniques against a set of objectives.

A technique is represented by AttackTechnique and built by an AttackTechniqueFactory. Concretely, in PyRIT terms, a technique can bundle:

  • the attack class (attack_class, an AttackStrategy subclass) and all its constructor args (attack_kwargs) — e.g. max_turns, tree_width/tree_depth, or an AttackConverterConfig of request/response converters;

  • an adversarial chat target (adversarial_chat) plus its system prompt (adversarial_system_prompt_path) and seed prompt (adversarial_seed_prompt), for attacks that drive a conversation;

  • a SeedAttackTechniqueGroup (seed_technique) of general-technique seeds, which can carry a system prompt, a prepended_conversation, a simulated_conversation (SeedSimulatedConversation), and a next_message;

  • the selection metadata that lets a scenario pick it: its name and strategy_tags.

The objective is not part of the technique — it stays separate and is supplied by the dataset at run time. You rarely build a technique by hand; instead you register a factory and let scenarios construct techniques on demand with the scenario’s own objective target and scorer.

Where techniques come from: initializers

Techniques are registered into a singleton AttackTechniqueRegistry by an initializer. The canonical catalog lives in ScenarioTechniqueInitializer, which registers a flat list of AttackTechniqueFactory instances. Each factory is self-describing — it knows its name, the attack class it builds, its tags, and whether it needs an adversarial chat target — so a scenario can construct the technique lazily with the scenario’s own objective target and scorer.

Registration is per-name idempotent, so initializers compose: run more than one and each adds only the techniques that aren’t already registered.

The cell below runs the initializer and lists the catalog.

import pandas as pd

from pyrit.registry.object_registries.attack_technique_registry import AttackTechniqueRegistry
from pyrit.setup import IN_MEMORY, initialize_pyrit_async
from pyrit.setup.initializers.components import ScenarioTechniqueInitializer

await initialize_pyrit_async(memory_db_type=IN_MEMORY, silent=True)  # type: ignore
await ScenarioTechniqueInitializer().initialize_async()  # type: ignore

factories = AttackTechniqueRegistry.get_registry_singleton().get_factories()

rows = [
    {
        "Technique": name,
        "Attack (executor)": f.attack_class.__name__,
        "Adversarial?": "yes" if f.uses_adversarial else "no",
        "Tags": ", ".join(f.strategy_tags),
    }
    for name, f in factories.items()
]

pd.set_option("display.max_rows", None)
pd.set_option("display.max_colwidth", None)
print(pd.DataFrame(rows).to_string(index=False))
                     Technique              Attack (executor) Adversarial?                              Tags
                     role_play                 RolePlayAttack          yes core, single_turn, default, light
                     many_shot        ManyShotJailbreakAttack           no  core, multi_turn, default, light
                           tap TreeOfAttacksWithPruningAttack          yes                  core, multi_turn
                          pair                     PAIRAttack          yes                  core, multi_turn
           crescendo_simulated            PromptSendingAttack          yes                 core, single_turn
                   red_teaming               RedTeamingAttack          yes           core, multi_turn, light
            context_compliance        ContextComplianceAttack          yes          core, single_turn, light
      crescendo_movie_director            PromptSendingAttack          yes                 core, single_turn
     crescendo_history_lecture            PromptSendingAttack          yes                 core, single_turn
crescendo_journalist_interview            PromptSendingAttack          yes                 core, single_turn
                violent_durian               RedTeamingAttack          yes                        multi_turn

How techniques are selected

Scenarios don’t reference factories directly. Instead, a scenario’s ScenarioStrategy enum is built from the registered factories: every technique becomes an enum member, and the factory’s tags become selectable aggregates. That gives you three ways to choose what runs:

  • By name — pick a single technique (e.g. role_play).

  • By aggregate tag — pick a group that expands to every matching technique. ALL is always present; tags like single_turn, multi_turn, default, and light come from the factories.

  • Composite — pair a technique with converters (see Common Scenario Parameters).

On the command line this is the --strategy flag of pyrit_scan; programmatically it’s the scenario_strategies argument to initialize_async. The grouping is what lets --strategy single_turn or --strategy light fan out to a whole family of techniques without naming each one.

Relationship to single-turn attacks

Many single-turn attacks are, in effect, attack techniques: a PromptSendingAttack paired with a specific set of seeds or a fixed configuration. crescendo_simulated and the persona-driven crescendo variants in the catalog above are exactly that — a plain PromptSendingAttack plus different seed groups. When you find yourself reaching for a one-off single-turn attack subclass, consider whether it would be better expressed as a registered technique so scenarios can select it by name and tag.

Defining your own

To add a technique, register a factory. The simplest form names an attack class and tags it:

from pyrit.executor.attack import RolePlayAttack, RolePlayPaths
from pyrit.registry.object_registries.attack_technique_registry import AttackTechniqueRegistry
from pyrit.scenario.core.attack_technique_factory import AttackTechniqueFactory

AttackTechniqueRegistry.get_registry_singleton().register_from_factories(
    [
        AttackTechniqueFactory(
            name="my_role_play",
            attack_class=RolePlayAttack,
            strategy_tags=["single_turn", "custom"],
            attack_kwargs={"role_play_definition_path": RolePlayPaths.MOVIE_SCRIPT.value},
        )
    ]
)

Wrap registration in a PyRITInitializer (as ScenarioTechniqueInitializer does) when you want it to run as part of standard setup. Any scenario built afterwards will see my_role_play as a selectable strategy.