Skip to main content

LLM-Shield-Proxy

Build Status PyPI: llm-shield-proxy PyPI: pii-leak-benchmark License Python Docs & Playground

This repository contains two related packages:

  1. pii-leak-benchmark tests an OpenAI-compatible streaming gateway. It checks whether the gateway sends the test values to its model provider and whether the client gets the original values back.
  2. LLM-Shield-Proxy is a self-hosted streaming privacy gateway. The benchmark tests it by name and applies the same publication rules used for every other gateway.

What changed after the first benchmark run

The six results below were produced by this project on one workstation. No outside contributor has repeated them yet, so the table marks every product result as unreplicated. Each result links to the exact configuration and the report produced by the run.

The first version of the test used invalid examples of an email address, SSN, and credit card:

Old test value Why Presidio rejected it
person@example.invalid .invalid is not a public domain suffix
123-45-6789 Presidio blocks this well-known invalid SSN sequence
4532-1234-5678-9012 The number fails the Luhn card-number checksum

LLM-Shield-Proxy matched the text patterns but did not perform those validity checks. This gave it an unfair advantage over detectors that validate values. A LiteLLM and Presidio run revealed the problem: the old values produced leaked: ["SSN"], while valid test values produced leaked: []. The project did not publish the affected result. It replaced the three values with valid, reserved test values and reran all six configurations. See the fixture threat model for the full record.

The benchmark also found two streaming bugs in LLM-Shield-Proxy. It created an OpenTelemetry span for every SSE event even when export was off, and it sent each event's blank terminator as a separate write. Both bugs are fixed and covered by tests/test_streaming_write_efficiency.py. The run record explains what changed.

Known limitation: the test uses three fixed data formats. A small program written specifically for those formats can pass without being a general PII detector. The values change on every run, but the formats do not. Testing more formats caused two false failures in six trials. See the fixture threat model for the measurements.

Run it yourself, in about a minute

pip install pii-leak-benchmark

# The negative control: no gateway at all, raw pass-through. MUST report outcome=fail.
pii-leak-benchmark \
  --target-base-url capture://self \
  --target-name raw-pass-through-negative-control --target-version 1 \
  --redaction-claimed claimed \
  --redaction-claim-citation https://github.com/ninadphalak/LLM-Shield-Proxy/blob/main/website/docs/conformance/reproducing.md \
  --redaction-enabled \
  --redaction-config-reference "synthetic control: declared redaction intentionally absent"

# Your gateway, already configured to send upstream traffic to http://127.0.0.1:8765/v1
pii-leak-benchmark --target-base-url http://127.0.0.1:4000/v1 --target-name your-gateway

The only third-party Python dependency is httpx; you do not need to install one gateway to test another. You configure the gateway to use the benchmark's local capture server as its model provider. The benchmark then checks the URL, headers, HTTP framing, and JSON body for the test values. If it cannot safely parse part of the request, the run ends with an error instead of assuming that no value leaked. The conformance docs describe the full method.

fail has one narrow meaning: the gateway sent an unmasked test value to the benchmark's capture server. A product that does not offer PII redaction is marked not-applicable, not failed. A one-way anonymizer that removes the values but does not restore them receives a separate outcome.

Results

Target Outcome Runs / distinct submitters
Raw capture endpoint (control) fail - three literal matches 1 / 1 - control, not a product
LLM-Shield-Proxy pass - 5/5 1 / 1 - unreplicated
LiteLLM 1.99.0, default redaction-not-enabled 1 / 1 - unreplicated
LiteLLM 1.99.0 + Presidio no-leak-profile-not-met (no leak) 1 / 1 - unreplicated
Portkey OSS 1.15.2, default redaction-not-enabled 1 / 1 - unreplicated
Portkey OSS 1.15.2 + regexReplace no-leak-profile-not-met (no leak) 1 / 1 - unreplicated

Every product result above was run once by this project's maintainer. It has not yet been repeated by an independent person. A result becomes replicated only after three different people each submit a run of the same gateway and configuration. Until then, it remains unreplicated. Full table, method and evidence · submit a run.

Run LLM-Shield-Proxy

pip install llm-shield-proxy
llm-shield-proxy --host 0.0.0.0 --port 8000
curl http://localhost:8000/healthz

For the container path:

docker compose up -d
curl http://localhost:8000/healthz
python examples/demo.py
Terminal demonstration of LLM-Shield-Proxy masking and streaming rehydration

LLM-Shield-Proxy is a self-hosted privacy gateway for OpenAI-compatible streaming APIs. It applies configured PII, PHI, PCI and secret transformations before the upstream, then rehydrates the masked values incrementally as SSE events arrive. Point an existing client at it by changing base_url:

from openai import OpenAI

client = OpenAI(api_key="your-shield-virtual-key", base_url="http://localhost:8000/v1")
stream = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Contact Sarah at sarah@example.com."}],
    stream=True,
)
for chunk in stream:
    print(chunk.choices[0].delta.content or "", end="")

A successful health check only means the server started. To send a model request, add the API key for your model provider and configure a key that clients will use to call the proxy. Start with .env.example, then follow the deployment guide.

How LLM-Shield-Proxy works

Before sending a request to the model provider, the proxy finds configured types of sensitive data and replaces their values. As the provider streams its response, the proxy joins replacement tokens that were split across SSE events and restores values that the client is allowed to receive. For structured JSON, it changes string values without changing the JSON syntax. Test this behavior with the schemas used by your provider and tools.

LLM privacy proxy dual-pipeline redaction architecture

The maintained component map and deployment diagrams live in the architecture guide, architecture whitepaper, and deployment guide.

Area What is implemented Where the evidence stops
Detection 10 native Tier 1 patterns, Tier 2 Shannon entropy, optional Tier 3 ONNX NER, BYOR rules Supported types · no recall guarantee on unlabeled traffic
Streaming privacy Sliding-window SSE rehydration, bounded streaming JSON lexer Architecture · conformance method
Masking Synthetic, structural-tag, scrub, operator-keyed stateless crypto Masking guide · plaintext still exists in process memory
Security controls SSRF/DNS-rebinding egress checks, request policy, rate and blast-radius limits, canary tripwires Security · not a substitute for network policy
Evidence plane Hash-linked audit records, Ed25519 receipts, OSCAL output, compliance packs Compliance overview · tamper-evident, not WORM without immutable retention
MCP governance Scoped JSON-RPC subset with RBAC and egress policy Research-scoped; MCP guide · not a complete MCP transport

Deployment choices

In standard mode, detection, masking, policy checks, and value restoration run inside your gateway. Only the masked request is sent to the external model provider:

Standard LLM privacy gateway deployment

In air-gapped mode, the masked request goes to an internal model gateway. Network policy must still block direct provider access, telemetry, and other unintended outbound traffic:

Air-gapped LLM egress gateway deployment

See deployment topologies, air-gapped egress, and the Kubernetes/Helm deployment guide.

Every feature is labelled Supported, Beta, Experimental, or Research. The label states how the feature was tested and what remains untested: feature catalog · stability policy · limitations.

It supports SOC 2, HIPAA, GDPR, EU AI Act and NIST/ISO evidence programs by supplying technical controls and artifacts. It does not certify a deployment, guarantee complete detection, or make network policy optional.

Verifying this repository

git clone https://github.com/ninadphalak/LLM-Shield-Proxy.git
cd LLM-Shield-Proxy
python -m pip install -e ./pii-leak-benchmark -e ".[dev]"
python -m pytest

The benchmark is a separate distribution in this repo, so it installs first; nothing in it imports the proxy and a test fails if that ever changes. CI provisions real Redis, an HTTP/2 ALPN server, a checksum-pinned ONNX export, Docker, Helm and promtool. A missing dependency fails those jobs rather than skipping them, so a green build cannot mean "nothing ran".

Documentation

Contributing, license, and citation

Contributions are welcome through issues, discussions and CONTRIBUTING.md. The most valuable contribution is an independent benchmark run against a gateway you operate, whether it matches or differs from a row above.

Source code is Apache 2.0; documentation and diagrams may carry CC BY 4.0 terms. See LICENSE.

The author identifies U.S. application numbers 64/126,730 and 64/139,263 as pending filings related to streaming transformation and structured stateless masking. Pending applications are not issued patents; verify status with counsel and official records before relying on them.

If you reference the architecture or benchmark methodology, use CITATION.cff or:

Phalak, N. (2026). Quantifying Latency and Token Overhead in Real-Time LLM Stream Sanitization: A Tiered Detection Approach. https://doi.org/10.5281/zenodo.21955770

Release files for llm-shield-proxy 1.5.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for llm-shield-proxy 1.5.2
File Size Uploaded
llm_shield_proxy-1.5.2.tar.gz 276.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for llm-shield-proxy 1.5.2
File Interpreter ABI Platform
llm_shield_proxy-1.5.2-py3-none-any.whl Python 3 none any Details

Total release size:446.6 kB

Release files / llm_shield_proxy-1.5.2.tar.gz

Download URL llm_shield_proxy-1.5.2.tar.gz
Size 276.4 kB
Tags Source
SHA-256 checksum
How to use checksums
dd45e54a14a8fc8d826c64c370c8b1f38b37e26f0eb4ff1221e02a91efdc6b25
BLAKE2b-256 checksum
How to use checksums
6157ce97c9376e9c486a83272e741ac4ea6deb85e62ff836bc274b60ec03bef2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release files / llm_shield_proxy-1.5.2-py3-none-any.whl

Download URL llm_shield_proxy-1.5.2-py3-none-any.whl
Size 170.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9d078529009ee600aeb6b32d88d6421edddcd758aca5b8628c26142e291c6672
BLAKE2b-256 checksum
How to use checksums
5f6eb53b63930efcb00daf6abcb157ab4db2a21ffed004e17726caa4af63cb1d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release history Release notifications | RSS feed

1.6.6

2 release files

1.6.5

2 release files

1.6.4

2 release files

1.6.3

2 release files

1.6.2

2 release files

1.6.1

2 release files

1.6.0

2 release files

This release

1.5.2 This release

2 release files

1.5.1

2 release files

1.4.0

2 release files

1.3.7

2 release files

1.3.6

2 release files

1.3.5

2 release files

1.3.4

2 release files

1.3.3

2 release files

1.3.2

2 release files

1.3.1

2 release files

1.3.0

2 release files

1.2.14

2 release files

1.2.13

2 release files

1.2.12

2 release files

1.2.11

2 release files

1.2.9

2 release files

1.2.7

2 release files

1.2.5

2 release files

1.0.20

2 release files

1.0.19

2 release files

1.0.18

2 release files

1.0.17

2 release files

1.0.16

2 release files

1.0.15

2 release files

1.0.14

2 release files

1.0.12

2 release files

1.0.10

2 release files

1.0.9

2 release files

1.0.8

2 release files

1.0.7

2 release files

1.0.6

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page