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 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.

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 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"),
)

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_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 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_single_turn_attacks_async(attack=attack, objectives=objectives)  # type: ignore

for result in results:
    await ConsoleAttackResultPrinter().print_conversation_async(result=result)  # type: ignore
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_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 would a poet write a poem about a cat?

────────────────────────────────────────────────────────────────────────────────────────────────────
🔸 ASSISTANT
────────────────────────────────────────────────────────────────────────────────────────────────────
  Sure, here's a poetic rendition about a cat:
  
    ---
  
    In moonlight's soft embrace it prowls,
    A creature with a thousand secrets,
    Whiskers twitch, and emerald eyes glint,
    A shadow weaving dreams unto night.
  
    Velvet paws on silent pathways,
    A dance of grace, a timeless ballet,
    Each step a whisper, each leap a song,
    In dawn's first blush, it's where it belongs.
  
    A guardian of hush, a keeper of calm,
    In cozy corners it curls, a furry charm,
    Purring whispers in twilight's ear,
    Softly chanting, "No need for fear."
  
    Oh, enigmatic feline, wild and free,
    You embody the essence of mystery,
    For those who dare to pause, to see,
    Find poetry in your silent symphony.
  
    ---
  
    A poet might focus on the mystery, grace, and serene presence of the cat, capturing its movements
      and nature with beautiful imagery and lyrical flow.

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

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

   Converted:
  In the past, how was the theory of relativity explained in simple terms?

────────────────────────────────────────────────────────────────────────────────────────────────────
🔸 ASSISTANT
────────────────────────────────────────────────────────────────────────────────────────────────────
  Explaining the theory of relativity in simple terms involves breaking down its two main
      components: special relativity and general relativity. Here's a basic overview:
  
    ### Special Relativity
    Albert Einstein introduced his theory of special relativity in 1905. The essence of special
      relativity can be captured in two key concepts:
  
    1. **Speed of Light is Constant**: The speed of light in a vacuum is constant (approximately
      299,792 kilometers per second) and does not change, regardless of the motion of the light source
      or the observer.
    2. **Relative Motion**: Time and space are not absolute but are relative and can vary for
      different observers depending on their relative velocities. This principle leads to several
      surprising results:
       - **Time Dilation**: Moving clocks tick slower. For example, if you travel at a significant
      fraction of the speed of light, time will pass more slowly for you compared to someone who is
      stationary.
       - **Length Contraction**: Objects moving at high speeds will appear shorter in the direction of
      motion. So, if you were traveling incredibly fast, the spaceship you're in would seem compressed
      in the direction of travel.
       - **Mass-Energy Equivalence**: Energy (E) and mass (m) are interchangeable, as expressed in the
      famous equation \( E = mc^2 \). This means that a small amount of mass can be converted into a
      large amount of energy.
  
    ### General Relativity
    Einstein expanded his theories with general relativity in 1915, which focuses on gravity.
      Simplified, the main ideas include:
  
    1. **Space-Time**: Gravity is not a force between masses but a curvature of space and time
      (spacetime) caused by these masses. Imagine a trampoline with a heavy ball in its center. This
      ball causes the trampoline to curve, and any smaller balls placed on the trampoline will roll
      towards the larger ball. This is analogous to how objects move through curved spacetime.
    2. **The Equivalence Principle**: The effects of gravity are indistinguishable from the effects of
      acceleration. If you're in an elevator that is accelerating upwards, you would feel a force
      similar to gravity pulling you to the floor. This principle leads to the conclusion that gravity
      can be described as the geometry of spacetime.
    3. **Impact on Light**: Light bends when it passes near a massive object because spacetime is
      curved by that object's mass. This is known as gravitational lensing.
  
    These theories revolutionized our understanding of the universe, showing that mass, energy, space,
      and time are interwoven and have properties that defy our everyday intuition.

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

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