Skip to main content

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 KeyProvider interface (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 StaticKeyProvider or load them automatically from environment variables using EnvKeyProvider (looks for PROXYPROMPT_ENCRYPTION_KEY by default). Interface stubs are provided for HashiCorp Vault, AWS KMS, Google Secret Manager, and Azure Key Vault.
  • Tamper Protection: EncryptedStore binds the AES-256-GCM ciphertext with the unique placeholder name as Authenticated Associated Data (AAD). If a database record is swapped or altered, decryption fails immediately with DecryptionError.

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

proxyprompt-0.1.0.tar.gz (45.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

proxyprompt-0.1.0-py3-none-any.whl (44.1 kB view details)

Uploaded Python 3

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

Hashes for proxyprompt-0.1.0.tar.gz
Algorithm Hash digest
SHA256 acb36cecb2699dab050d1d0aca8d828010fc57f8ffb84e3099df985836745652
MD5 9e4204ac2dac131cc25620e7bb79c14d
BLAKE2b-256 7bddda965e457ac9fcaaab09a6cdc1bf4ede5c6e191e276bf1e3fe95ae1c359e

See more details on using hashes here.

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

Hashes for proxyprompt-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9ae444eb67493f1b237fce21dcbb192d7281d8745175cb73e17856b5aad6deb1
MD5 93ea85821eddf892e149cbef661fef16
BLAKE2b-256 7c58150f9ae60e15fcfdc163d92c0afdd778b011124fdb75a7a7b9281ba37c06

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page