A Python SDK for Masking Sensitive Data Before Sending to LLMs
Project description
ProxyPrompt
ProxyPrompt is a production-quality, high-performance Python SDK designed to detect, mask, and unmask sensitive or proprietary information (PII, credentials, database schemas, IP addresses, etc.) in text prompts before sending them to Large Language Models (LLMs). It works transparently with any LLM provider (OpenAI, Anthropic, Gemini, Ollama, Groq, etc.) and integrates smoothly into popular web frameworks (FastAPI, Flask) and agent orchestrators (LangChain, LlamaIndex).
Features
- 30+ Built-in Detectors: URL, Email, Phone, API Keys, JWT, UUID, IPv4/v6, MAC Addresses, Credit Cards, Windows/Linux Paths, Database/Table/Column Names, SQL Queries, JSON, XML, HTML, Markdown Links, and Cloud Secrets (AWS, Azure, Google).
- Secure Key Management: Supports industry-standard AES-256-GCM encryption for storing original values. Features a pluggable
KeyProviderinterface (env variables, static keys, Vault, AWS KMS, etc.) to keep secrets out of repositories. - Streaming Unmasking: Includes a high-efficiency sliding-buffer stream unmasker that reconstructs placeholder tokens split across arbitrary stream chunks and unmasks them on-the-fly.
- Pluggable Storage Backends: Memory, JSON file, SQLite, and Redis stores.
- Extensible Plugin System: Register custom regex detectors dynamically in one line.
- Middlewares & Callback Handlers: Pre-built wrappers for OpenAI, Anthropic, Gemini, Ollama, Groq, LangChain, LlamaIndex, FastAPI, and Flask.
- Production CLI: CLI commands to mask, unmask, inspect, clean, and monitor stats.
Installation
Install using pip:
pip install proxyprompt
To install optional dependencies (like Redis):
pip install proxyprompt[redis]
Quick Start
Basic Usage
from proxyprompt import mask, unmask
# 1. Mask sensitive details in a prompt
prompt = "Please send database dump of customer_prod to admin@company.com immediately."
req = mask(prompt)
print(req.text)
# Output: "Please send database dump of <DATABASE_1> to <EMAIL_1> immediately."
print(req.thread_id)
# Output: "8e91af92" (Secure random hex ID)
# 2. Send masked prompt to LLM...
# response = client.chat(req.text)
response_text = "Sent database dump of <DATABASE_1> to <EMAIL_1> successfully."
# 3. Unmask original values in the LLM response
final = unmask(response_text, thread_id=req.thread_id)
print(final)
# Output: "Sent database dump of customer_prod to admin@company.com successfully."
Configured Mask Instance
from proxyprompt import Mask
mask_engine = Mask(
store="sqlite", # Persistence backend
db_path="my_mappings.db",
encryption=True, # Enable AES-256-GCM
sensitive_schema_names=["payments_tbl", "ssn_col"] # Database Schema overrides
)
res = mask_engine.mask("Query tables payments_tbl or ssn_col.")
print(res.text)
# Output: "Query tables <DATABASE_1> or <DATABASE_2>."
Streaming Response Unmasking
When LLM responses stream token-by-token, placeholder brackets can be split across chunks (e.g. <LI in Chunk 1, and NK_1> in Chunk 2). ProxyPrompt implements a sliding-window buffer that guarantees correct restoration with $O(N)$ time complexity and minimal memory footprint:
# Synchronous Stream
stream_generator = client.chat.completions.create(prompt=req.text, stream=True)
unmasked_stream = mask_engine.unmask_stream(stream_generator, thread_id=req.thread_id)
for chunk in unmasked_stream:
print(chunk, end="")
Middleware Integrations
OpenAI SDK Wrapper
Wrap the OpenAI client to automatically mask prompts and unmask completions (supports streaming and async):
import openai
from proxyprompt.middleware import wrap_openai
client = wrap_openai(openai.OpenAI())
# Prompts are masked outgoing, responses are unmasked incoming automatically
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "My private API key is AIzaSyA1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6Q"}]
)
FastAPI Middleware
Apply ASGI middleware to intercept, mask, and unmask HTTP payloads:
from fastapi import FastAPI
from proxyprompt.middleware import FastAPIMaskMiddleware
app = FastAPI()
app.add_middleware(FastAPIMaskMiddleware, target_keys=["prompt", "query"])
LangChain Callbacks
from langchain.chat_models import ChatOpenAI
from proxyprompt.middleware import LangChainMaskCallbackHandler
handler = LangChainMaskCallbackHandler()
chat = ChatOpenAI(callbacks=[handler])
Advanced: Dynamic Plugins
mask_engine = Mask()
mask_engine.register_detector(
name="Employee ID",
regex=r"EMP\d{5}",
placeholder="EMPLOYEE"
)
res = mask_engine.mask("EMP12345 joined the channel.")
print(res.text) # Output: "<EMPLOYEE_1> joined the channel."
Storage Backends
| Backend | Initialization | Persistence | Note |
|---|---|---|---|
MemoryStore |
Mask(store="memory") |
Ephemeral | Default, thread-safe |
JsonStore |
Mask(store="json", db_path="store.json") |
File-based | Lightweight file persistence |
SQLiteStore |
Mask(store="sqlite", db_path="store.db") |
DB-based | Robust concurrency (WAL mode) |
RedisStore |
Mask(store="redis", redis_url="redis://...") |
Distributed | Perfect for clustered LLM apps |
Security Guidelines
- Zero Keys in Config: Never save AES keys inside git repositories or YAML configs.
- Key Providers: Supply keys programmatically via
StaticKeyProvideror load them automatically from environment variables usingEnvKeyProvider(looks forPROXYPROMPT_ENCRYPTION_KEYby default). Interface stubs are provided for HashiCorp Vault, AWS KMS, Google Secret Manager, and Azure Key Vault. - Tamper Protection:
EncryptedStorebinds the AES-256-GCM ciphertext with the uniqueplaceholdername as Authenticated Associated Data (AAD). If a database record is swapped or altered, decryption fails immediately withDecryptionError.
CLI Usage
ProxyPrompt includes a Click-powered CLI:
# Mask file contents (defaults to persistent JSON file store for CLI runs)
proxyprompt mask input.txt -o masked.txt
# Unmask file contents
proxyprompt unmask masked.txt -t <thread_id> -o unmasked.txt
# Inspect mappings
proxyprompt inspect <thread_id>
# Run cleanup of expired mappings (older than 24h)
proxyprompt clean --expiration 86400
# View statistics
proxyprompt stats
License
This project is licensed under the MIT License.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file proxyprompt-0.1.0.tar.gz.
File metadata
- Download URL: proxyprompt-0.1.0.tar.gz
- Upload date:
- Size: 45.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
acb36cecb2699dab050d1d0aca8d828010fc57f8ffb84e3099df985836745652
|
|
| MD5 |
9e4204ac2dac131cc25620e7bb79c14d
|
|
| BLAKE2b-256 |
7bddda965e457ac9fcaaab09a6cdc1bf4ede5c6e191e276bf1e3fe95ae1c359e
|
File details
Details for the file proxyprompt-0.1.0-py3-none-any.whl.
File metadata
- Download URL: proxyprompt-0.1.0-py3-none-any.whl
- Upload date:
- Size: 44.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9ae444eb67493f1b237fce21dcbb192d7281d8745175cb73e17856b5aad6deb1
|
|
| MD5 |
93ea85821eddf892e149cbef661fef16
|
|
| BLAKE2b-256 |
7c58150f9ae60e15fcfdc163d92c0afdd778b011124fdb75a7a7b9281ba37c06
|