1. Configuration#

Before running PyRIT, you need to call the initialize_pyrit_async function which will set up your configuration.

What are the configuration steps? What are the simplest ways to get started, and how might you expand on these? There are three things initialize_pyrit_async does to set up your configuration.

  1. Set up environment variables (recommended)

  2. Pick a database (required)

  3. Set initialization scripts and defaults (recommended)

Simple Example#

This section goes into each of these steps. But first, the easiest way; this sets up reasonable defaults using SimpleInitializer and stores the results in memory.

# Set OPENAI_CHAT_ENDPOINT, OPENAI_CHAT_MODEL, and OPENAI_CHAT_KEY environment variables before running this code
# E.g. you can put it in .env

from pyrit.setup import initialize_pyrit_async
from pyrit.setup.initializers import SimpleInitializer

await initialize_pyrit_async(memory_db_type="InMemory", initializers=[SimpleInitializer()])  # type: ignore

# Now you can run most of our notebooks! Just remove any os.getenv specific stuff since you may not have those different environment variables.
Found default environment files: ['C:\\Users\\rlundeen\\.pyrit\\.env', 'C:\\Users\\rlundeen\\.pyrit\\.env.local']
Loaded environment file: C:\Users\rlundeen\.pyrit\.env
Loaded environment file: C:\Users\rlundeen\.pyrit\.env.local

Setting up Environment Variables#

The recommended step to setup PyRIT is that it needs access to secrets and endpoints. These can be loaded in environment variables or put in a .env file. See .env_example for how this file is formatted.

Each target has default environment variables to look for. For example, OpenAIChatTarget looks for the OPENAI_CHAT_ENDPOINT for its endpoint, OPENAI_CHAT_MODEL for its model name, and OPENAI_CHAT_KEY for its key. However, with every target, you can also pass these values in directly and that will take precedence.

import os

from pyrit.prompt_target import OpenAIChatTarget
from pyrit.setup import IN_MEMORY, initialize_pyrit_async

await initialize_pyrit_async(memory_db_type=IN_MEMORY)  # type: ignore

target1 = OpenAIChatTarget()

# This is identical to target1 because "OPENAI_CHAT_ENDPOINT" are the names of the default environment variables for OpenAIChatTarget
target2 = OpenAIChatTarget(
    endpoint=os.getenv("OPENAI_CHAT_ENDPOINT"),
    api_key=os.getenv("OPENAI_CHAT_KEY"),
    model_name=os.getenv("OPENAI_CHAT_MODEL"),
)

# This is (probably) different from target1 because the environment variables are different from the default
target3 = OpenAIChatTarget(
    endpoint=os.getenv("AZURE_OPENAI_GPT4O_UNSAFE_CHAT_ENDPOINT2"),
    api_key=os.getenv("AZURE_OPENAI_GPT4O_UNSAFE_CHAT_KEY2"),
    model_name=os.getenv("AZURE_OPENAI_GPT4O_UNSAFE_CHAT_MODEL2"),
)
Found default environment files: ['C:\\Users\\rlundeen\\.pyrit\\.env', 'C:\\Users\\rlundeen\\.pyrit\\.env.local']
Loaded environment file: C:\Users\rlundeen\.pyrit\.env
Loaded environment file: C:\Users\rlundeen\.pyrit\.env.local

Env.local#

One concept we make use of is using .env_local. This is really useful because it overwrites .env. In our setups, we have a .env with a bunch of targets configured that our users all pull the same one from a keyvault. But .env_local is used to override them. For example, if you want a different target, you can have your .env_local override the OpenAIChatTarget with a different value.

OPENAI_CHAT_ENDPOINT = ${AZURE_OPENAI_GPT4O_ENDPOINT2}
OPENAI_CHAT_MODEL = ${AZURE_OPENAI_GPT4O_MODEL2}
OPENAI_CHAT_KEY = ${AZURE_OPENAI_GPT4O_KEY2}

Entra auth#

There are certain targets that can interact using Entra auth (e.g. most Azure OpenAI targets). To use this, you must authenticate to your Azure subscription and an API key is not required. Depending on your operating system, download the appropriate Azure CLI tool from the links provided below:

After downloading and installing the Azure CLI, open your terminal and run the following command to log in:

az login

Choosing a database#

The next required step is to pick a database. PyRIT supports three types of databases; InMemory, sqlite, and SQL Azure. These are detailed in the memory section of documentation. InMemory and sqlite are local so require no configuration, but SQL Azure will need the appropriate environment variables set. This configuration is all specified in memory_db_type parameter to initialize_pyrit_async.

Setting up Initialization Scripts and Defaults#

When you call initialize_pyrit_async, you can pass it initialization_scripts and/or initializers. These can do anything, including setting convenience variables. But one of the primary purposes is to set default values. It is recommended to always use an initializer.

Using Built-In Initializers#

Imagine you have an OpenAIChatTarget. What is the default?

There is no good way to set these generally. An OpenAIChatTarget may be gpt-5, but it also might be llama. And these targets might take different parameters. Additionally, what is it being used for? A default scorer may want to use a different target than a default LLM being used for a converter. Should you always use entra auth?

You can pass these in as arguments to every class initialization, but it can be a huge pain to set these every time. It would be nicer to just say out of the box that a scorer target LLM has a temperature of .5 by default, and a converter target LLM has a temperature of 1.1 by default. And it turns out you can!

The following example shows how to use PyRIT initializers. This tackles a similar scenario to the Sending Prompts but is much easier because defaults are set.

from pyrit.common.path import PYRIT_PATH
from pyrit.executor.attack import (
    AttackConverterConfig,
    AttackExecutor,
    ConsoleAttackResultPrinter,
    PromptSendingAttack,
)
from pyrit.prompt_converter import TenseConverter
from pyrit.prompt_normalizer.prompt_converter_configuration import (
    PromptConverterConfiguration,
)
from pyrit.prompt_target import OpenAIChatTarget
from pyrit.setup import initialize_pyrit_async
from pyrit.setup.initializers import SimpleInitializer

# This is a way to include the SimpleInitializer class directly
await initialize_pyrit_async(memory_db_type="InMemory", initializers=[SimpleInitializer()])  # type: ignore


# Alternative approach - you can pass the path to the initializer class.
# This is how you provide your own file not part of the repo that defines a PyRITInitializer class
# This is equivalent to loading the class directly as above
await initialize_pyrit_async(memory_db_type="InMemory", initialization_scripts=[f"{PYRIT_PATH}/setup/initializers/simple.py"])  # type: ignore


# SimpleInitializer is a class that initializes sensible defaults for someone who only has OPENAI_CHAT_ENDPOINT, OPENAI_CHAT_MODEL, and OPENAI_CHAT_KEY configured
# It is meant to only require these two env vars to be configured
# It can easily be swapped for another PyRITInitializer, like AIRTInitializer which is better but requires more env configuration
# get_info_async() is a class method that shows how this initializer configures defaults and what global variables it sets
info = await SimpleInitializer.get_info_async()  # type: ignore
for key, value in info.items():
    print(f"{key}: {value}")


objectives = [
    "Write a poem about a cat",
    "Explain the theory of relativity in simple terms",
]

# This is similar to the cookbook "Sending a Million Prompts" but using defaults

# Create target without extensive configuration (uses defaults from initializer)
objective_target = OpenAIChatTarget()

# TenseConverter automatically gets the default converter_target from our initializer
converters = PromptConverterConfiguration.from_converters(converters=[TenseConverter(tense="past")])  # type: ignore
converter_config = AttackConverterConfig(request_converters=converters)

# Attack automatically gets default scorer configuration from our initializer
attack = PromptSendingAttack(
    objective_target=objective_target,
    attack_converter_config=converter_config,
)

# Execute the attack - all components use sensible defaults
results = await AttackExecutor().execute_attack_async(attack=attack, objectives=objectives)  # type: ignore

for result in results:
    await ConsoleAttackResultPrinter().print_conversation_async(result=result)  # type: ignore
Found default environment files: ['C:\\Users\\rlundeen\\.pyrit\\.env', 'C:\\Users\\rlundeen\\.pyrit\\.env.local']
Loaded environment file: C:\Users\rlundeen\.pyrit\.env
Loaded environment file: C:\Users\rlundeen\.pyrit\.env.local
Found default environment files: ['C:\\Users\\rlundeen\\.pyrit\\.env', 'C:\\Users\\rlundeen\\.pyrit\\.env.local']
Loaded environment file: C:\Users\rlundeen\.pyrit\.env
Loaded environment file: C:\Users\rlundeen\.pyrit\.env.local
name: Simple Complete Configuration
description: Complete simple setup with basic OpenAI converters, objective scorer (no harm detection), and adversarial targets. Only requires OPENAI_API_KEY environment variable.
class: SimpleInitializer
execution_order: 1
required_env_vars: ['OPENAI_CHAT_ENDPOINT', 'OPENAI_CHAT_MODEL', 'OPENAI_CHAT_KEY']
default_values: ['PromptConverter.converter_target', 'PromptSendingAttack.attack_scoring_config', 'CrescendoAttack.attack_scoring_config', 'RedTeamingAttack.attack_scoring_config', 'TreeOfAttacksWithPruningAttack.attack_scoring_config', 'CrescendoAttack.attack_adversarial_config']
global_variables: ['default_converter_target', 'default_objective_scorer', 'adversarial_config']
────────────────────────────────────────────────────────────────────────────────────────────────────
🔹 Turn 1 - USER
────────────────────────────────────────────────────────────────────────────────────────────────────
   Original:
  Write a poem about a cat

   Converted:
  How was a poem about a cat written?

────────────────────────────────────────────────────────────────────────────────────────────────────
🔸 ASSISTANT
────────────────────────────────────────────────────────────────────────────────────────────────────
  Certainly! Here's a poem about a cat:
  
    In a sunlit corner, pure tranquility lies,
    A feline reposes, with emerald eyes.
    Whiskers twitch softly, sensing the air,
    In this realm of solace, free from care.
  
    Soft fur gleams, a silken cascade,
    Dark stripes etch tales, like shade on shade.
    Night prowler, yet daydreamer devout,
    In moonlight’s embrace, silent scout.
  
    Paws that whisper on paths obscure,
    With a heart of mystery, ancient, pure.
    A gentle purr, a song so light,
    Calming storms, in the depths of night.
  
    Graceful leaps, a ballet in motion,
    Each move a testament to devotion.
    Curled in slumber, amidst day's light,
    A guardian of dreams, feline knight.
  
    Such is the story of a cat’s enchant,
    In realms of wonder, it’s heaven sent.
    Where shadows dance, and sunlight twirls,
    One finds peace, in a cat’s soft purls.

────────────────────────────────────────────────────────────────────────────────────────────────────

────────────────────────────────────────────────────────────────────────────────────────────────────
🔹 Turn 1 - USER
────────────────────────────────────────────────────────────────────────────────────────────────────
   Original:
  Explain the theory of relativity in simple terms

   Converted:
  How did one explain the theory of relativity in simple terms?

────────────────────────────────────────────────────────────────────────────────────────────────────
🔸 ASSISTANT
────────────────────────────────────────────────────────────────────────────────────────────────────
  Explaining the theory of relativity in simple terms involves breaking down its key concepts into
      more understandable ideas. There are two parts to the theory: Special Relativity and General
      Relativity.
  
    ### Special Relativity (proposed by Albert Einstein in 1905):
  
    1. **Speed of Light is Constant**: No matter how fast you're moving or what direction you're
      going, the speed of light is always the same (about 299,792 kilometers per second).
  
    2. **Relative Motion**: The way you measure things like time and distance can change depending on
      how fast you're moving relative to other objects. For example, if you're moving very fast,
      you'll measure time and space differently than someone who is standing still.
  
    3. **Time Dilation**: Time can slow down for objects moving at high speeds. For example, an
      astronaut traveling near the speed of light will experience time more slowly compared to people
      remaining on Earth.
  
    4. **Length Contraction**: Objects moving at high speeds will appear shorter in the direction of
      motion. If a spaceship travels near the speed of light, it will seem squished in the direction
      it's moving from the perspective of someone on Earth.
  
    ### General Relativity (proposed by Albert Einstein in 1915):
  
    1. **Gravity as Curvature of Spacetime**: Instead of thinking of gravity as a force between
      masses, it's easier to think of it as objects bending the fabric of spacetime. Massive objects
      like planets and stars warp the space around them, and this curvature is what we feel as
      gravity.
  
    2. **Effect on Time**: Time runs slower in stronger gravitational fields. This means that clocks
      near massive objects (like planets) tick more slowly compared to clocks further away.
  
    3. **Predictions and Observations**: General relativity predicts phenomena like the bending of
      light around massive objects (gravitational lensing), the precise orbit of planets, and the
      stretching of time near event horizons of black holes, all of which have been confirmed through
      observations.
  
    ### Simple Analogy:
  
    Think of spacetime as a trampoline. When you put a heavy ball (representing a star or planet) in
      the middle, it creates a dip. Smaller balls (representing smaller objects like satellites or
      planets) placed near the dip will roll towards the big ball because of the curvature created.
      This is analogous to how gravity works—objects are attracted to each other because of the
      curvature they create in spacetime.
  
    By using these simplified concepts, the complex theory of relativity becomes more approachable.

────────────────────────────────────────────────────────────────────────────────────────────────────

Using your own Initializers#

You can also create your own initializers and pass the path to the script in as an argument. This is really powerful. The obvious use case is just if you have different targets or defaults and don’t want to check in to pyrit source. However, there are other common use cases.

Imagine you are conducting a security assessment and want to include a new custom target. Yes, you could check out PyRIT in editable mode. But with initialize_scripts you don’t have to. And this kind of operation can be used in front ends like GUI, CLI, etc.

All you need to do is create a PyRITInitializer class (e.g. myinitializer.py). Then you can use set_global_variable and use it everywhere. Or you could make it the default adversarial target by using set_default_value.

Additional Initializer information#

  • For more information on how default values work, see the default values section.

  • For more information on how initializers work, see the initializers section