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.

pyrit.scenario

High-level scenario classes for running attack configurations.

AtomicAttack

Represents a single atomic attack test combining an attack strategy and dataset.

An AtomicAttack is an executable unit that executes a configured attack against all objectives in a dataset. Multiple AtomicAttacks can be grouped together into larger test scenarios for comprehensive security testing and evaluation.

The AtomicAttack uses SeedAttackGroups as the single source of truth for objectives, prepended conversations, and next messages. Each SeedAttackGroup must have an objective set.

An AttackTechnique bundles the attack strategy with an optional SeedAttackTechniqueGroup, cleanly separating “how to attack” from “what to attack” (the objective).

Constructor Parameters:

ParameterTypeDescription
atomic_attack_namestrUnique key for this atomic attack. Used for resume tracking and result persistence — must be unique across all AtomicAttack instances in a scenario.
display_group`strNone`
attack_technique`AttackTechniqueNone`
attack`AttackStrategy[Any, Any]None`
seed_groupslist[SeedAttackGroup]List of seed attack groups. Each must be a SeedAttackGroup (which guarantees exactly one objective).
adversarial_chatOptional[PromptTarget]Optional chat target for generating adversarial prompts or simulated conversations. Defaults to None.
objective_scorerOptional[TrueFalseScorer]Optional scorer for evaluating simulated conversations. Defaults to None.
memory_labelsOptional[dict[str, str]]Additional labels to apply to prompts. Defaults to None.
**attack_execute_paramsAnyAdditional parameters to pass to the attack execution method. Defaults to {}.

Methods:

drop_seed_groups_with_hashes

drop_seed_groups_with_hashes(hashes: set[str]) → None

Drop seed groups whose objective_sha256 is in hashes.

This is the resume filter: within an atomic attack, objective_sha256 is the stable identity (enforced unique by __init__). Content-derived keys are robust to reordering and resampling, so resume produces the right remaining-work set even when get_seed_groups() is rebuilt from scratch on each run_async().

ParameterTypeDescription
hashesset[str]SHA256 hashes of objective text for seed groups to drop (typically those that have already produced a non-error AttackResult).

filter_seed_groups_by_objectives

filter_seed_groups_by_objectives(remaining_objectives: list[str]) → None

Filter seed groups to only those with objectives in the remaining list.

.. deprecated:: Use drop_seed_groups_with_hashes (or keep_seed_groups_with_hashes) which keys on content-addressed objective_sha256 instead of objective text. Scheduled for removal in 0.16.0.

ParameterTypeDescription
remaining_objectivesList[str]List of objectives that still need to be executed.

keep_seed_groups_with_hashes

keep_seed_groups_with_hashes(hashes: set[str]) → set[str]

Keep only seed groups whose objective_sha256 is in hashes.

Inverse of drop_seed_groups_with_hashes: used on resume to replay the originally-sampled subset and ignore any seed groups that were added since (or that landed in this run’s fresh random.sample draw and are no longer in the persisted set).

ParameterTypeDescription
hashesset[str]SHA256 hashes of objective text for seed groups to keep.

Returns:

run_async

run_async(executor: AttackExecutor | None = None, return_partial_on_failure: bool = True, max_concurrency: int | None = None, attack_params: Any = {}) → AttackExecutorResult[AttackResult]

Execute the atomic attack against all seed groups.

This method uses AttackExecutor to run the configured attack against all seed groups. Concurrency is owned by the executor: pass a shared AttackExecutor instance to share a single budget across multiple atomic attacks (this is how Scenario parallelizes them).

When return_partial_on_failure=True (default), this method will return an AttackExecutorResult containing both completed results and incomplete objectives (those that didn’t finish execution due to exceptions). This allows scenarios to save progress and retry only the incomplete objectives.

Note: “completed” means the execution finished, not that the attack objective was achieved. “incomplete” means execution didn’t finish (threw an exception).

ParameterTypeDescription
executor`AttackExecutorNone`
return_partial_on_failureboolIf True, returns partial results even when some objectives don’t complete execution. If False, raises an exception on any execution failure. Defaults to True. Defaults to True.
max_concurrency`intNone`
**attack_paramsAnyAdditional parameters to pass to the attack strategy. Defaults to {}.

Returns:

Raises:

set_scenario_result_id

set_scenario_result_id(scenario_result_id: str | None) → None

Bind this atomic attack to a scenario result for attribution.

Called by Scenario._execute_scenario_async before each run_async so persisted AttackResult rows carry the attribution_parent_id foreign key back to the scenario. Pass None to clear the binding (e.g. when running an atomic attack outside of a scenario).

ParameterTypeDescription
scenario_result_id`strNone`

AttackTechnique

Bases: Identifiable

Bundles an attack strategy with an optional technique seed group.

An AttackTechnique encapsulates the full attack configuration — the strategy (including its target, converters, and scorer) plus any reusable technique seeds (e.g. jailbreak templates). The objectives that define which weaknesses to probe live separately on the SeedAttackGroup / AtomicAttack.

AttackTechniqueFactory

Bases: Identifiable

A self-describing factory that produces AttackTechnique instances on demand.

Captures technique-specific configuration (name, strategy tags, converters, adversarial config, tree depth, etc.) at construction time. Produces fresh, fully-constructed attacks by calling the real constructor with the captured params plus scenario-specific objective_target and scoring config.

Validates kwargs against the attack class constructor signature at construction time, catching typos and incompatible parameter names early.

Constructor Parameters:

ParameterTypeDescription
namestrRegistry name for this technique. This is used as the scenario strategy name.
attack_classtype[AttackStrategy[Any, Any]]The AttackStrategy subclass to instantiate.
strategy_tags`list[str]None`
attack_kwargs`dict[str, Any]None`
adversarial_config`AttackAdversarialConfigNone`
seed_technique`SeedAttackTechniqueGroupNone`
uses_adversarial`boolNone`
scorer_override_policyScorerOverridePolicyWhat to do when a scenario’s scorer is incompatible with the attack’s attack_scoring_config type annotation. Defaults to WARN. Defaults to ScorerOverridePolicy.WARN.

Methods:

create

create(objective_target: PromptTarget, attack_scoring_config: AttackScoringConfig, attack_adversarial_config_override: AttackAdversarialConfig | None = None, attack_converter_config_override: AttackConverterConfig | None = None) → AttackTechnique

Create a fresh AttackTechnique bound to the given target.

Each call produces a fully independent attack instance by calling the real constructor. Config objects frozen at factory construction time are deep-copied into every new instance.

The *_override parameters let a caller replace a config that was baked into the factory at construction time. When None (the default), the factory’s original config is kept as-is — so baked-in converters, adversarial targets, etc. are preserved automatically.

Override configs are only forwarded when the attack class constructor declares a matching parameter (without the _override suffix). This allows a single call site to safely pass all available overrides without breaking attacks that don’t support them.

ParameterTypeDescription
objective_targetPromptTargetThe target to attack (always required at create time).
attack_scoring_configAttackScoringConfigThe scoring config to use for the attack. This is important for attacks like TAP that may need a more specific scorer than the scorer the scenario provides.
attack_adversarial_config_override`AttackAdversarialConfigNone`
attack_converter_config_override`AttackConverterConfigNone`

Returns:

Raises:

with_simulated_conversation

with_simulated_conversation(name: str, attack_class: type[AttackStrategy[Any, Any]] | None = None, adversarial_chat_system_prompt_path: str | Path | None = None, next_message_system_prompt_path: str | Path | None = None, num_turns: int = 3, strategy_tags: list[str] | None = None, attack_kwargs: dict[str, Any] | None = None, adversarial_config: AttackAdversarialConfig | None = None, uses_adversarial: bool | None = None, scorer_override_policy: ScorerOverridePolicy = ScorerOverridePolicy.WARN) → AttackTechniqueFactory

Alternative constructor that builds a SeedSimulatedConversation inline.

Wraps a single SeedSimulatedConversation in a SeedAttackTechniqueGroup and assigns it as seed_technique so callers don’t have to construct both manually. All other parameters are forwarded to __init__.

ParameterTypeDescription
namestrRegistry name for this technique. When other defaults are used, name also picks the canonical YAML at EXECUTOR_SEED_PROMPT_PATH/red_teaming/{name}.yaml.
attack_class`type[AttackStrategy[Any, Any]]None`
adversarial_chat_system_prompt_path`strPath
next_message_system_prompt_path`strPath
num_turnsintNumber of simulated conversation turns. Defaults to 3. Defaults to 3.
strategy_tags`list[str]None`
attack_kwargs`dict[str, Any]None`
adversarial_config`AttackAdversarialConfigNone`
uses_adversarial`boolNone`
scorer_override_policyScorerOverridePolicyPolicy applied when a scenario’s scorer is incompatible with the attack’s attack_scoring_config type annotation. Defaults to WARN. Forwarded to the factory constructor. Defaults to ScorerOverridePolicy.WARN.

Returns:

BaselineAttackPolicy

Bases: Enum

Declares how a scenario type treats the default baseline atomic attack.

The baseline is a plain PromptSendingAttack that sends each objective unmodified, used as a comparison point against the scenario’s strategies. Each scenario class declares its policy via Scenario.BASELINE_ATTACK_POLICY; callers can still override at runtime via initialize_async(include_baseline=...) for the Enabled and Disabled states.

DatasetConfiguration

Configuration for scenario datasets.

This class provides a unified way to specify the dataset source for scenarios. Only ONE of seed_groups or dataset_names can be set.

Constructor Parameters:

ParameterTypeDescription
seed_groupsOptional[List[SeedGroup]]Explicit list of SeedGroup to use. Defaults to None.
dataset_namesOptional[List[str]]Names of datasets to load from memory. Defaults to None.
max_dataset_sizeOptional[int]If set, randomly samples up to this many SeedGroups (without replacement). Defaults to None.
scenario_strategiesOptional[Sequence[ScenarioStrategy]]The scenario strategies being executed. Subclasses can use this to filter or customize which seed groups are loaded. Defaults to None.

Methods:

get_all_seed_attack_groups

get_all_seed_attack_groups() → list[SeedAttackGroup]

Resolve and return all seed groups as SeedAttackGroups in a flat list.

This is a convenience method that calls get_seed_attack_groups() and flattens the results into a single list. Use this for attack scenarios that need SeedAttackGroup functionality.

Returns:

Raises:

get_all_seed_groups

get_all_seed_groups() → list[SeedGroup]

Resolve and return all seed groups as a flat list.

This is a convenience method that calls get_seed_groups() and flattens the results into a single list. Use this when you don’t need to track which dataset each seed group came from.

Returns:

Raises:

get_all_seeds

get_all_seeds() → list[Seed]

Load all seed prompts from memory for all configured datasets.

This is a convenience method that retrieves SeedPrompt objects directly from memory for all configured datasets. If max_dataset_size is set, randomly samples up to that many prompts per dataset (without replacement).

Returns:

Raises:

get_default_dataset_names

get_default_dataset_names() → list[str]

Get the list of default dataset names for this configuration.

This is used by the CLI to display what datasets the scenario uses by default.

Returns:

get_seed_attack_groups

get_seed_attack_groups() → dict[str, list[SeedAttackGroup]]

Resolve and return seed groups as SeedAttackGroups, grouped by dataset.

This wraps get_seed_groups() and converts each SeedGroup to a SeedAttackGroup. Use this when you need attack-specific functionality like objectives, prepended conversations, or simulated conversation configuration.

Returns:

Raises:

get_seed_groups

get_seed_groups() → dict[str, list[SeedGroup]]

Resolve and return seed groups based on the configuration.

This method handles all resolution logic:

  1. If seed_groups is set, use those directly (under key ‘_explicit_seed_groups’)

  2. If dataset_names is set, load from memory using those names

In all cases, max_dataset_size is applied per dataset if set.

Subclasses can override this to filter or customize which seed groups are loaded based on the stored scenario_composites.

Returns:

Raises:

has_data_source

has_data_source() → bool

Check if this configuration has a data source configured.

Returns:

Parameter

Describes a parameter that a PyRIT component (initializer or scenario) accepts.

Scenario

Bases: ABC

Groups and executes multiple AtomicAttack instances sequentially.

A Scenario represents a comprehensive testing campaign composed of multiple atomic attack tests (AtomicAttacks). It executes each AtomicAttack in sequence and aggregates the results into a ScenarioResult.

Constructor Parameters:

ParameterTypeDescription
namestrDescriptive name for the scenario. Defaults to ''.
versionintVersion number of the scenario.
strategy_classType[ScenarioStrategy]The strategy enum class for this scenario.
default_strategyScenarioStrategyThe default strategy member used when no scenario_strategies are passed to initialize_async. Usually an aggregate member like MyStrategy.ALL or MyStrategy.DEFAULT.
default_dataset_configDatasetConfigurationThe default dataset configuration used when no dataset_config is passed to initialize_async.
objective_scorerScorerThe objective scorer used to evaluate attack results.
scenario_result_idOptional[Union[uuid.UUID, str]]Optional ID of an existing scenario result to resume. Can be either a UUID object or a string representation of a UUID. If provided and found in memory, the scenario will resume from prior progress. All other parameters must still match the stored scenario configuration. Defaults to None.
include_default_baseline`boolNone`

Methods:

initialize_async

initialize_async(objective_target: PromptTarget = REQUIRED_VALUE, scenario_strategies: Optional[Sequence[ScenarioStrategy]] = None, dataset_config: Optional[DatasetConfiguration] = None, max_concurrency: int = 4, max_retries: int = 0, memory_labels: Optional[dict[str, str]] = None, include_baseline: bool | None = None) → None

Initialize the scenario by populating self._atomic_attacks and creating the ScenarioResult.

This method allows scenarios to be initialized with atomic attacks after construction, which is useful when atomic attacks require async operations to be built.

If a scenario_result_id was provided in init, this method will check if it exists in memory and validate that the stored scenario matches the current configuration. If it matches, the scenario will resume from prior progress. If it doesn’t match or doesn’t exist, a new scenario result will be created.

ParameterTypeDescription
objective_targetPromptTargetThe target system to attack. Defaults to REQUIRED_VALUE.
scenario_strategiesOptional[Sequence[ScenarioStrategy]]The strategies to execute. Can be a list of ScenarioStrategy enum members. If None, uses the default aggregate from the scenario’s configuration. Defaults to None.
dataset_configOptional[DatasetConfiguration]Configuration for the dataset source. Use this to specify dataset names or maximum dataset size from the CLI. If not provided, scenarios use their constructor-supplied default_dataset_config. Defaults to None.
max_concurrencyintMaximum number of concurrent units of work for the scenario. Defaults to 4. A “unit of work” is one parameter-build call (turning a seed group into attack parameters) or one attack execution (running a single objective × attack pair). All atomic attacks in the scenario share a single AttackExecutor whose internal semaphore caps in-flight units at max_concurrency: e.g. max_concurrency=4 means at most 4 such units are in flight at any time, regardless of how many atomic attacks or objectives the scenario has. Defaults to 4.
max_retriesintMaximum number of automatic retries if the scenario raises an exception. Set to 0 (default) for no automatic retries. If set to a positive number, the scenario will automatically retry up to this many times after an exception. For example, max_retries=3 allows up to 4 total attempts (1 initial + 3 retries). Defaults to 0.
memory_labelsOptional[Dict[str, str]]Additional labels to apply to all attack runs in the scenario. These help track and categorize the scenario. Defaults to None.
include_baseline`boolNone`

Raises:

run_async

run_async() → ScenarioResult

Execute all atomic attacks in the scenario sequentially.

Each AtomicAttack is executed in order, and all results are aggregated into a ScenarioResult containing the scenario metadata and all attack results. This method supports resumption - if the scenario raises an exception partway through, calling run_async again will skip already-completed objectives.

If max_retries is set, the scenario will automatically retry after an exception up to the specified number of times. Each retry will resume from where it left off, skipping completed objectives.

Returns:

Raises:

set_params_from_args

set_params_from_args(args: dict[str, Any]) → None

Populate self.params from merged CLI / config arguments.

Coerces each value to its declared param_type, validates, and materializes declared defaults for params not in args. Every declared parameter is guaranteed a key in self.params after this call; params without a declared default land as None.

ParameterTypeDescription
argsdict[str, Any]Map of parameter name to raw value. Keys with None values are treated as absent (YAML null). Argparse callers should use argparse.SUPPRESS.

Raises:

supported_parameters

supported_parameters() → list[Parameter]

Override to declare custom parameters this scenario accepts.

Declared parameters flow from CLI/config through set_params_from_args into self.params before initialize_async() runs. Implemented as a classmethod so --list-scenarios can introspect without instantiating.

Note: PyRITInitializer.supported_parameters is an instance @property; this asymmetry is intentional pending a future alignment.

Returns:

ScenarioCompositeStrategy

Represents a composition of one or more attack strategies.

This class encapsulates a collection of ScenarioStrategy instances along with an auto-generated descriptive name, making it easy to represent both single strategies and composed multi-strategy attacks.

The name is automatically derived from the strategies:

Constructor Parameters:

ParameterTypeDescription
strategiesSequence[ScenarioStrategy]The sequence of strategies in this composition. Must contain at least one strategy.

ScenarioIdentifier

Bases: BaseModel

Identifier describing the executed scenario.

Methods:

from_dict

from_dict(data: dict[str, Any]) → ScenarioIdentifier

Reconstruct a ScenarioIdentifier from a dictionary.

Deprecated: use model_validate(...) instead.

ParameterTypeDescription
datadict[str, Any]Dictionary as produced by model_dump(by_alias=True).

Returns:

to_dict

to_dict() → dict[str, Any]

Serialize to a JSON-compatible dictionary.

Deprecated: use model_dump(by_alias=True) instead.

Returns:

ScenarioResult

Bases: BaseModel

Scenario result class for aggregating scenario results.

Methods:

from_dict

from_dict(data: dict[str, Any]) → ScenarioResult

Reconstruct a ScenarioResult from a dictionary.

Deprecated: use model_validate(...) instead.

ParameterTypeDescription
datadict[str, Any]Dictionary as produced by model_dump(mode="json").

Returns:

get_display_groups

get_display_groups() → dict[str, list[AttackResult]]

Aggregate attack results by display group.

When a display_group_map was provided, results from multiple atomic_attack_name keys that share the same display group are merged into a single list. When no map was provided, this returns the same structure as attack_results (identity mapping).

Returns:

get_objectives

get_objectives(atomic_attack_name: str | None = None) → list[str]

Get the list of unique objectives for this scenario.

ParameterTypeDescription
atomic_attack_name`strNone`

Returns:

get_strategies_used

get_strategies_used() → list[str]

Get the list of strategies used in this scenario.

Returns:

normalize_scenario_name

normalize_scenario_name(scenario_name: str) → str

Normalize a scenario name to match the stored class name format.

Converts CLI-style snake_case names (e.g., “foundry” or “content_harms”) to PascalCase class names (e.g., “Foundry” or “ContentHarms”) for database queries. If the input is already in PascalCase or doesn’t match the snake_case pattern, it is returned unchanged.

This is the inverse of ScenarioRegistry._class_name_to_scenario_name().

ParameterTypeDescription
scenario_namestrThe scenario name to normalize.

Returns:

objective_achieved_rate

objective_achieved_rate(atomic_attack_name: str | None = None) → int

Get the success rate of this scenario.

ParameterTypeDescription
atomic_attack_name`strNone`

Returns:

to_dict

to_dict() → dict[str, Any]

Serialize this scenario result to a JSON-compatible dictionary.

Deprecated: use model_dump(mode="json", by_alias=True) instead.

Returns:

ScenarioStrategy

Bases: Enum

Base class for attack strategies with tag-based categorization and aggregation.

This class provides a pattern for defining attack strategies as enums where each strategy has a set of tags for flexible categorization. It supports aggregate tags (like “easy”, “moderate”, “difficult” or “fast”, “medium”) that automatically expand to include all strategies with that tag.

Convention: Strategy enum members should map 1:1 to selectable attack techniques (e.g., PromptSending, RolePlay, TAP) or to aggregates of techniques (e.g., DEFAULT, SINGLE_TURN). Datasets control what content or objectives are tested; strategies control how attacks are executed. Avoid encoding dataset or category selection into the strategy enum — use DatasetConfiguration and the --dataset-names CLI flag for that axis.

Tags: Flexible categorization system where strategies can have multiple tags (e.g., {“easy”, “converter”}, {“difficult”, “multi_turn”})

Subclasses should define their enum members with (value, tags) tuples and override the get_aggregate_tags() classmethod to specify which tags represent aggregates that should expand.

Convention: All subclasses should include ALL = ("all", {"all"}) as the first aggregate member. The base class automatically handles expanding “all” to include all non-aggregate strategies.

The normalization process automatically:

  1. Expands aggregate tags into their constituent strategies

  2. Excludes the aggregate tag enum members themselves from the final set

  3. Handles the special “all” tag by expanding to all non-aggregate strategies

Methods:

expand

expand(strategies: set[T]) → list[T]

Expand a set of strategies (including aggregates) into an ordered, deduplicated list.

Aggregate markers (like EASY, ALL) are expanded into their constituent concrete strategies. The result is sorted by enum definition order for determinism.

ParameterTypeDescription
strategiesset[T]Set of strategies, which may include aggregate markers.

Returns:

get_aggregate_strategies

get_aggregate_strategies() → list[T]

Get all aggregate strategies for this strategy enum.

This method returns only the aggregate markers (like ALL, EASY, MODERATE, DIFFICULT) that are used to group concrete strategies by tags.

Returns:

get_aggregate_tags

get_aggregate_tags() → set[str]

Get the set of tags that represent aggregate categories.

Subclasses should override this method to specify which tags are aggregate markers (e.g., {“easy”, “moderate”, “difficult”} for complexity-based scenarios or {“fast”, “medium”} for speed-based scenarios).

The base class automatically includes “all” as an aggregate tag that expands to all non-aggregate strategies.

Returns:

get_all_strategies

get_all_strategies() → list[T]

Get all non-aggregate strategies for this strategy enum.

This method returns all concrete attack strategies, excluding aggregate markers (like ALL, EASY, MODERATE, DIFFICULT) that are used for grouping.

Returns:

get_strategies_by_tag

get_strategies_by_tag(tag: str) → set[T]

Get all attack strategies that have a specific tag.

This method returns concrete attack strategies (not aggregate markers) that include the specified tag.

ParameterTypeDescription
tagstrThe tag to filter by (e.g., “easy”, “converter”, “multi_turn”).

Returns:

normalize_strategies

normalize_strategies(strategies: set[T]) → set[T]

Normalize a set of attack strategies by expanding aggregate tags.

This method processes a set of strategies and expands any aggregate tags (like EASY, MODERATE, DIFFICULT or FAST, MEDIUM) into their constituent concrete strategies. The aggregate tag markers themselves are removed from the result.

The special “all” tag is automatically supported and expands to all non-aggregate strategies.

ParameterTypeDescription
strategiesSet[T]The initial set of attack strategies, which may include aggregate tags.

Returns:

resolve

resolve(strategies: Sequence[Any] | None, default: T) → list[T]

Resolve strategy inputs into a concrete, ordered, deduplicated list.

Handles None (returns expanded default), plain strategies, and aggregate strategies. Non-cls items (e.g., ScenarioCompositeStrategy) are silently skipped for backward compatibility.

ParameterTypeDescription
strategies`Sequence[Any]None`
defaultTDefault aggregate strategy to use when strategies is None or empty.

Returns: