BPL Logo Banner
CareersContact

Red teaming of AI-enabled systems is becoming essential for every organization to ensure they aren’t introducing risk to themselves and their stakeholders as they implement generative AI applications. Pentesters and red teamers need to become familiar with AI-specific attack techniques and terminology.

Microsoft has put out some AI Red-Teaming Playground Labs that are a great way to practice attacking AI applications. In this series of blog posts, we’ll walk through some of these challenges and uncover AI red-teaming tactics, techniques, and procedures (TTPs) that you can add to your arsenal.

Installation/Setup

The setup is a bit of effort initially, but I promise it’s worth it and won’t take much once it’s running. We’ll create an Azure account if you don’t already have one, set up an AI deployment for the Playground to use, then install and connect the Playground itself. Finally, effective offensive security testing should combine both automated and manual testing, so we’ll set up Microsoft’s PyRIT framework so we can walk through each challenge both manually and programmatically.

If you don’t have an Azure account, let’s set one up real quick. Cloud stuff always feels intentionally obscure and overly-complicated, so I’ll try to be detailed, but don’t blame me if this part is a pain. Also be aware of costs – new Azure accounts get $200 in free credits, and for this setup and Challenge 1 testing I’ve only used $0.09 of that, so no big deal here but just know that billing is happening in the background.

Here are the steps I took:

If all that worked successfully, congrats because it took me an embarrassingly long time to get to this point on the first pass. Let’s continue:

Success! Now you’ve got two models for the AI Red-Teaming Playground Labs to communicate with.

Install docker compose if you don’t have it already – if you’re using Kali like me, remember do not use apt install docker-compose! Do this instead:

apt install -y docker.io
mkdir -p ~/.docker/cli-plugins/
curl -SL https://github.com/docker/compose/releases/download/v2.24.6/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose`
chmod +x ~/.docker/cli-plugins/docker-compose
docker compose version

This is a great time to mention that docker is my archnemesis and it always causes me personal pain to recommend using it, but here we are.

Next is setting up the labs locally. Pull down the git repo:

git clone https://github.com/microsoft/AI-Red-Teaming-Playground-Labs.git

The repo has a .env.example file in it. Copy this to .env and follow the instructions inside it to create a SECRET_KEY and an AUTH_KEY, then populate the rest with your Azure endpoint and API key saved previously. Set the model as “gpt-4o”.

And that should be it! Within that directory, run:

docker compose up

Then navigate to http://localhost:5000/login?auth=<AUTH_KEY> and you should see a list of challenges to launch.

Finally, we’ll install PyRIT, which is Microsoft’s open-source framework for automating security testing of generative AI applications. Its documentation can also be obscure and needs a little more detail in my opinion, but we’ll do our best to figure it out.

Install pyrit, jupyter, and ipykernel:

pip install pyrit jupyter ipykernel

Install kernelspec:

python -m ipykernel install --user --name=pyrit_kernel

Setup complete!

Challenge 1 – Manual

Challenge 1 – Direct Prompt Injection is straightforward and simple enough to do manually. The exact same prompt won’t work 100% of the time due to the nature of GenAI being non-deterministic and all that, but you shouldn’t have much of a problem convincing the chat bot to give up its passwords.txt.

Challenge 1 – Automated with PyRIT

I recommend poking around the PyRIT documentation and watching at least this high-level walkthrough from Microsoft. Even better, watch all 10 quick episodes of their AI Red-Teaming 101 course.

At a high-level, here’s what’s happening in PyRIT:

Datasets = Initial prompts to be fed into the pipeline.

Orchestrator = from their docs: “The Orchestrator is a top-level component that red team operators will interact with the most. It is responsible for telling PyRIT which endpoints to connect to and how to send prompts. It can be thought of as the component that executes an attack technique.”

Converters = converts the prompts into something else – it could be different encoding, putting prompts into a Word doc instead of just plain text, or much more complex things like the MathPromptConverter which is used to “transform user queries into symbolic mathematical problems by applying set theory, abstract algebra, and symbolic logic”. We’ll look at a few of these in a second.

Target = an AI target and how to connect to it. For this it will be an HTTPTarget but other examples include OpenAIChatTarget, AzureBlobStorageTarget, and HuggingFaceChatTarget.

ScoringEngine = to avoid manually reviewing every chat response, you can set up scorers that will automatically grade responses to see if they meet set criteria. We won’t do this today but you’ll want this when doing high-volume testing.

Ok let’s launch the Jupyter notebook. For some of these labs, Microsoft has included a notebook to start with for PyRIT testing.

jupyter notebook

When the web GUI launches, select File -> New -> Notebook and choose the pyrit_kernel when prompted for Kernel. On the right, Upload and choose “AI-Red-Teaming-Playground-Labs/notebooks/Lab 1 – Credential exfiltraiton.ipynb”.

Follow the instructions to fill in the raw_http_request variable – don’t forget to adjust the curly braces according to step 7, and then put your prompt variable into the “input” parameter as shown below. Run the first cell and double check the print output looks as expected.

Note: if you ever get a JSONDecode error running the second cell (where it makes requests to the Lab 1 challenge HTTP endpoint) it’s likely due to a 401 response because the session cookie expired – you’ll need a new cookie/request here.

Note 2: if you see a duckdb error about unhashable type, this is a known bug in the newest duckdb (1.40), revert to 1.3.2 with pip install "duckdb==1.3.2"

Now that we’ve got a valid POST request that will send prompts to the Challenge 1 endpoint, let’s look into Converters to see how the initial prompt can be manipulated. Since I want to test out a bunch of Converters, in the first cell I changed the prompt converter import statement to get all of them:

from pyrit.prompt_converter import *

In the second cell, when it defines the HTTPTarget, add the parameter “use_tls=False” at the end or else you’ll get SSL errors (as the challenges are HTTP only). It should now look like:

http_prompt_target = HTTPTarget(http_request=raw_http_request, callback_function=parsing_function, timeout=20.0, use_tls=False)

CharacterSpaceConverter is a simple option to test first. It does exactly as advertised – puts a space between every character. Within the orchestrator, set the prompt_converter to CharacterSpaceConverter and run the notebook – you should see the converted prompt and the chat bot’s response.

Within the repo, you can find a list of all the built-in converters inside “PyRIT/pyrit/prompt_converter/__init__.py” (at the time of testing, I counted 61 total). Play around with different converters to see what options you have. You can stack multiple Converters as well and they’ll execute sequentially – here’s Leetspeak followed by CharacterSpace:

For a more complicated Converter, I tried MathPromptConverter, which frames the prompt as advanced math logic to see if it will complete the “math problem” which might get you past security controls. This and some other Converters require an LLM resource that PyRIT can use to generate advanced prompt mutations (and yes, you’re using GenAI to generate attacks against GenAI, this is life now).

Fortunately we just set up an Azure OpenAI endpoint for the Playground Labs and can re-use that same resource. You will need to define the endpoint details (found in Azure AI Foundry -> Deployment -> gpt-4o) within the code or in a .env file as explained in the PyRIT documentation.

We’ll do it directly in the code for now. Add an OpenAIChatTarget for this out-of-band prompt generation and give it the model name, API key, and endpoint. Within the orchestrator function call, add the MathPromptConverter and point it to the OpenAIChatTarget you just defined. The code should look similar to below (I’ve redacted my endpoint details):

Take a second to thank the universe you didn’t have to dig up old high school calculus textbooks to craft this prompt. Unfortunately here, the Challenge 1 chat bot didn’t fall for the math trap.

Playing with the Converters was interesting and there are plenty of techniques to try. The first to succeed in retrieving passwords.txt was the PersuasionConverter using the option “expert_endorsement”:

And that’s it for Challenge 1! Despite the simple example, it’s easy to see the potential here for automating large scale testing of AI implementations. We’ll be back soon for Challenge 2 – Metaprompt Extraction.

Author Image

About the Author

Ray Blasko is the Technical Director for offensive operations at BreakPoint Labs and a Red Team Operator for a DoD-certified Red Team, responsible for assessing and securing critical ICS/SCADA assets. He is recognized as a subject matter expert in both attacking and defending IT and OT environments, and he excels at resolving the technical and strategic issues that arise in protecting critical infrastructure. Ray holds numerous professional certifications and regularly presents at DoD Red Team conferences, trade conventions, and information security events.

Software testing is more than just a step in the development process; it’s a critical practice that drives the quality, security, and reliability of the software we deliver. At BreakPoint Labs, we’ve integrated rigorous testing throughout the entire development lifecycle, ensuring that every piece of software we produce meets our high standards and aligns with the needs of our clients and end users’ expectations.

Integrated Testing Throughout the Lifecycle

We believe in embedding testing into every phase of the development lifecycle, starting from the earliest stages and continuing through to post-deployment. By designing and executing tests from the beginning, issues or bugs are caught early, preventing them from escalating into larger problems. This proactive approach, combined with continuous testing as the software evolves, ensures a smoother development process and results in a more robust, reliable final product or service.

Embracing Automation

Leveraging technology to deliver effective and sustainable capabilities is a core tenant of BreakPoint Labs.  Automation is a key part of our testing strategy. By automating repetitive and complex tests, we can quickly verify that our software works as intended under various conditions. This not only saves time but also improves accuracy and consistency, giving us the confidence that our software and services can handle real-world demands under realistic constraints and against sophisticated actors.

A Comprehensive Testing Strategy

Our approach to testing is comprehensive and covers every aspect of the software:

Each of these testing methods is designed to address specific aspects of the software, ensuring that the final product is well-rounded and ready for deployment.

Building Confidence and Streamlining the ATO Process

Rigorous testing isn’t just about making sure the software works—it’s about building trust. Thorough testing gives stakeholders the confidence that the software will perform reliably in the real world.

Additionally, our detailed testing process supports the Authority to Operate (ATO) process. By documenting every step of our testing, we create artifacts that are essential for gate analysis and compliance reviews. These artifacts demonstrate that the software meets all security and operational requirements, making it easier to secure the necessary approvals and get the software into the hands of users quickly and efficiently.  A good example that we will dig into is “chaos testing”.

Chaos Testing

When writing chaos tests, the objective is to introduce failures and observe how the system responds to ensure resilience. Using a tool like ChaosToolkit, you can simulate various failure scenarios, such as resource constraints or random service disruptions. In one of my tests on a sample Django application, we found that it handled the load when utilizing 1-3 CPU cores but failed when pushed to 4 cores, uncovering scalability issues. In this stress test, the tool was configured to fully utilize 4 CPU cores for 10 seconds, simulating a heavy computational workload that the application could not handle under the increased pressure. Another test involved randomly restarting containers to verify they would come back up and remain accessible, which is essential for maintaining high availability. When writing chaos tests, start with a clear hypothesis, such as ensuring services remain functional under stress or after restarts. Use tools like ChaosToolkit to automate these tests in controlled environments, and always monitor logs for unexpected behaviors. 

Test Scenarios utilized ChaosToolKit, Django, and Docker

Django Application successfully handling 3 CPU cores of stress:

Django Application failing to handle 4 CPU cores of stress:

In summary, our software testing approach is more than just catching bugs. It’s about ensuring quality, building trust, and supporting compliance so that every piece of software we deliver is ready to perform when it matters most.

chevron-down