Securely Injecting Sensitive Data into Agents

Introduction & Lesson Overview

Welcome to a new course in your learning path! In the previous course, you learned how to connect your OpenAI agents to external tools and data sources using the Model Context Protocol (MCP). You saw how to safely manage connections and extend your agent's abilities by integrating with MCP servers. Now, you are ready to take on a new challenge: handling sensitive data securely within your agent workflows.

In this lesson, you will learn how to inject sensitive information—such as user names, passport numbers, or other private details—into your agent's runtime in a way that keeps this data hidden from the language model (LLM) itself. This is a crucial skill for building real-world applications, where privacy and security are top priorities. You will see how to use the RunContextWrapper class from the OpenAI Agents SDK to wrap and manage sensitive context, ensuring that only your trusted code and tools can access it, while the LLM remains unaware of any private details.

By the end of this lesson, you will be able to securely pass sensitive data to your agent's tools and keep it out of the LLM's reach.

Understanding the Risks of Exposing Sensitive Data

Before we dive into the technical details, let's remind ourselves why handling sensitive data with care is so important. When you work with LLMs, any data you send to the model could potentially be exposed in its outputs. This means that if you pass private information—like a user's passport number or personal address—directly to the LLM, there is a risk that this data could leak out in a response, be logged, or even be accessed by someone who shouldn't see it.

These risks are not just theoretical. Data leakage can lead to privacy breaches, security vulnerabilities, and even legal trouble if you violate regulations like GDPR or CCPA. For example, if an LLM is "jailbroken" or manipulated, it might reveal information it was never supposed to share. That's why it's critical to keep sensitive data out of the LLM's input and output streams whenever possible. Instead, you want to keep this data local—only accessible to your own code and trusted tools.

Managing Sensitive Data with RunContextWrapper

To help you manage sensitive data securely, the OpenAI Agents SDK provides the RunContextWrapper class. This class acts as a secure container for any context you want to pass into your agent's runtime. When you use RunContextWrapper, your sensitive data is kept local to your application and is never sent to the LLM. Instead, it is only available to your function tools, lifecycle hooks, or other trusted code that you control.

Here's how the SDK enables secure context injection in simple terms:

  1. You create your sensitive data object - This can be any Python object (like a dataclass or Pydantic model) containing private information you want to keep secure.

  2. You pass it to Runner.run() as context - When you call Runner.run(context=your_data), the SDK automatically wraps your data in a RunContextWrapper behind the scenes.

  3. The LLM sees your tool function description, not your data - When you define a tool function like book_hotel(context: RunContextWrapper[UserData], hotel_name: str), the LLM only sees a simplified description like "book_hotel(hotel_name: str)". The context parameter is completely hidden from the LLM's view.

  4. The LLM calls the function normally - Based on the user's request ("book me a room at Grand Plaza Hotel"), the LLM decides to call book_hotel(hotel_name="Grand Plaza Hotel"). It doesn't know about or need to provide the sensitive context.

  5. The SDK automatically injects your sensitive data - When the LLM calls the function, the SDK intercepts this call and automatically adds your sensitive context as the first parameter before executing your function.

  6. Your function receives both the LLM's parameters and your sensitive data - Your function gets called with both the context (injected by the SDK) and the hotel name (provided by the LLM).

  7. The LLM only sees the function's return value - After your function completes, the LLM receives only the return value (like "Booking confirmed for Alice Smith..."), never the sensitive data itself.

The RunContextWrapper is automatically created when you pass a context object to Runner.run(). However, it's important to understand that this wrapper is not magically injected into all functions. Only functions that explicitly declare a parameter of type RunContextWrapper[YourContextType] as their first parameter will receive the context. This design ensures that only functions requiring access to the run context receive it, while others remain unaffected. The wrapper also provides a usage attribute, which tracks things like token usage for the current run, but the most important feature for this lesson is its ability to keep your context private and secure.

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal