Skip to content

Add opt-in request redaction middleware - #31

Open
jszzr wants to merge 1 commit into
NVIDIA-AI-Blueprints:v3from
jszzr:zzr/presidio-redaction
Open

Add opt-in request redaction middleware#31
jszzr wants to merge 1 commit into
NVIDIA-AI-Blueprints:v3from
jszzr:zzr/presidio-redaction

Conversation

@jszzr

@jszzr jszzr commented Jun 15, 2026

Copy link
Copy Markdown

Summary

Adds an opt-in local request redaction layer for the in-process LiteLLM proxy path.
When enabled, /v1/chat/completions JSON request bodies are redacted before LiteLLM forwards them to an upstream provider.

The feature is disabled by default and uses a lazy Presidio backend so existing proxy deployments do not need the optional privacy dependencies unless redaction is explicitly enabled.

The initial default Presidio entity scope is intentionally narrow:

  • email addresses
  • phone numbers
  • US SSNs
  • dates and dates of birth
  • URLs
  • person names
  • selected geographic entities
  • organization and company names

Motivation

The router already sits on the host-side path between local clients and upstream model providers. This change adds a best-effort data minimization hook at that boundary for common prompt-level personal data, while preserving current behavior when the feature is not enabled.

Design

  • Adds a model-router-toolkit[privacy] optional extra for Presidio dependencies.
  • Adds a small privacy module with:
    • environment-driven redaction config
    • no-op backend for default behavior
    • lazy Presidio backend
    • OpenAI-compatible chat payload traversal
    • ASGI middleware for /v1/chat/completions
  • Installs the middleware from the in-process LiteLLM proxy only when MODEL_ROUTER_REDACTION_ENABLED=true.
  • Preserves request JSON structure and only rewrites text-bearing chat message content.
  • Leaves tools, function schemas, images, and arbitrary metadata untouched.

Evaluation context

I evaluated Presidio separately on the first 5,000 examples from nvidia/Nemotron-PII test split using en_core_web_sm and threshold 0.35. For the comparable entity subset aligned with this PR scope:

  • character recall: 0.8837
  • character F1: 0.6918
  • span overlap recall: 0.9821
  • full span coverage recall: 0.8313

Selected full span coverage recall:

Label Full coverage recall
email 0.9972
phone_number 0.9964
ssn 0.9974
date_of_birth 1.0000
date 0.9327
first_name 0.8470
last_name 0.8565
city 0.8142
county 0.8932

This is why the initial default scope is limited to common entities where Presidio is useful as a local best-effort backend.

Non-goals

This PR does not claim complete PII protection. It does not add query-aware minimization, output de-anonymization, broad sensitive attribute classification, or custom recognizers for credentials/API keys.

Validation

  • pytest tests/test_redaction.py tests/test_redaction_middleware.py -q
    • 11 passed in 0.11s
  • python -m ruff check src/model_router_toolkit/privacy src/model_router_toolkit/adapters/litellm/proxy.py tests/test_redaction.py tests/test_redaction_middleware.py
    • All checks passed!

I also tried a broader local run with pytest -q -m "not slow and not requires_torch"; it failed on pre-existing environment/tooling issues unrelated to this diff: httpx.AsyncClient(app=...) incompatibility and nvidia-smi returning [N/A] for GPU memory on this server.

@jszzr
jszzr force-pushed the zzr/presidio-redaction branch from 0b1b51a to 3463296 Compare June 15, 2026 07:58
@jszzr
jszzr marked this pull request as ready for review June 16, 2026 06:04
@jszzr

jszzr commented Jun 16, 2026

Copy link
Copy Markdown
Author

This PR is intended as the router-side prerequisite for an optional NemoClaw routed-inference pre-cloud redaction integration. The implementation is deliberately opt-in and scoped to the LiteLLM proxy request path so existing deployments keep their current behavior unless MODEL_ROUTER_REDACTION_ENABLED=true is set.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant