pii-shield-llm 🔒
Safe LLM usage by automatically masking PII/PFI before it leaves your system.
pii-shield-llm intercepts sensitive data, replaces it with typed UUID tokens (EMAIL_3f2a1b), sends the clean text to your LLM, then restores original values in the response — all transparently.
Installation
pip install pii-shield-llm # core (regex detection only)
pip install "pii-shield-llm[nlp]" # + spaCy NER for names & orgs
pip install "pii-shield-llm[openai]" # + OpenAI wrapper
pip install "pii-shield-llm[anthropic]" # + Anthropic wrapper
pip install "pii-shield-llm[all]" # everything
Quick Start
Basic masking & restoration
from pii_shield import PIISession
with PIISession() as session:
masked, mapping = session.mask(
"Hi, I'm Alice Smith. Reach me at alice@acme.com or 415-555-0199."
)
print(masked)
# → "Hi, I'm Alice Smith. Reach me at <<EMAIL_d3a1f9>> or <<PHONE_7b2c04>>."
# (Names need spaCy NER; emails & phones detected by regex)
llm_response = your_llm_call(masked) # send safe text to LLM
clean = session.restore(llm_response) # PII restored in response
print(clean)
# Session auto-saved to encrypted vault on context manager exit
With the built-in LLM wrapper (OpenAI)
import openai
from pii_shield import PIISession
from pii_shield.llm_client import LLMClient
client = LLMClient(
session=PIISession(),
backend="openai",
openai_client=openai.OpenAI(),
model="gpt-4o",
system_prompt="You are a helpful customer support agent.",
)
result = client.chat(
"Please look up account for john@corp.com, SSN 123-45-6789."
)
print(result.restored_text) # PII restored
print(result.masked_prompt) # What was actually sent to OpenAI
With Anthropic Claude
import anthropic
from pii_shield import PIISession
from pii_shield.llm_client import LLMClient
client = LLMClient(
session=PIISession(),
backend="anthropic",
anthropic_client=anthropic.Anthropic(),
model="claude-sonnet-4-20250514",
)
result = client.chat("Summarise the risk profile for card 4111111111111111.")
print(result.restored_text)
Multi-turn conversation
client = LLMClient(session=PIISession(), backend="openai", openai_client=..., model="gpt-4o")
r1 = client.chat("My name is Bob and my email is bob@corp.com.")
r2 = client.chat("What was the email I just gave you?")
# History is maintained; PII masked/restored across all turns
Entity Types Detected
| Entity | Method | Example |
|---|---|---|
EMAIL |
Regex | alice@acme.com |
PHONE |
Regex | +1 415-555-0199 |
SSN |
Regex | 123-45-6789 |
CREDIT_CARD |
Regex + Luhn | 4111 1111 1111 1111 |
ADDRESS |
Regex | 123 Main St, NY 10001 |
IP_ADDRESS |
Regex | 192.168.1.100 |
PASSPORT |
Regex | A12345678 |
DOB |
Regex | 01/15/1990 |
NAME |
spaCy NER* | Alice Smith |
ORG |
spaCy NER* | Goldman Sachs |
*Requires pip install "pii-shield-llm[nlp]" + python -m spacy download en_core_web_sm
Token Format
<<ENTITY_TYPE_shortid>>
Examples:
<<EMAIL_d3a1f9>>
<<PHONE_7b2c04>>
<<SSN_1a9e3c>>
<<CREDIT_CARD_f00b12>>
- Deterministic within a session: same raw value → same token (LLM output stays coherent)
- Cross-session isolated: different sessions never share tokens
- Type-preserving: LLM sees the entity category without the actual data
Vault & Key Management
Session mappings are persisted in an AES-encrypted file (Fernet / AES-128-CBC + HMAC-SHA256).
On first use, a key is auto-generated and written to .env:
PII_SHIELD_KEY="base64url-encoded-32-byte-key"
Keep this key safe — losing it means mappings in the vault cannot be decrypted.
To use a custom vault path or bring your own key:
from pii_shield import PIIVault, PIISession
vault = PIIVault(
vault_path="/secure/path/pii.vault.enc",
env_path="/secure/path/.env",
)
session = PIISession(vault=vault)
Advanced Usage
Restrict entity types
from pii_shield import PIISession, EntityType
session = PIISession(entity_types=[EntityType.EMAIL, EntityType.CREDIT_CARD])
Resume a named session
# Session 1 — mask and save
s = PIISession(session_id="order-12345")
masked, _ = s.mask("Card: 4111111111111111")
s.save()
# Later — restore using the same session
s2 = PIISession(session_id="order-12345")
print(s2.restore(masked)) # → "Card: 4111111111111111"
Custom LLM backend
def my_llm(prompt: str) -> str:
# Call your own model
return my_model.generate(prompt)
client = LLMClient(session=PIISession(), backend="custom", custom_fn=my_llm)
Architecture
Input Text
│
▼
[PIIDetector] regex patterns + optional spaCy NER
│
▼
[PIIReplacer] value → <<TYPE_shortid>> (deterministic, collision-safe)
│
▼
Masked Text ──→ LLM API (OpenAI / Anthropic / custom)
│
▼
LLM Response (may echo tokens back)
│
▼
[PIIRestorer] <<TYPE_shortid>> → original value
│
▼
Restored Output
[PIIVault] ←→ AES-encrypted session mappings on disk
Running Tests
pip install pytest
pytest tests/ -v
License
MIT
Metadata
Release files for pii-shield-llm 1.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pii_shield_llm-1.0.2.tar.gz | 18.4 kB | With provenance | Details for pii_shield_llm-1.0.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pii_shield_llm-1.0.2-py3-none-any.whl | Python 3 | none | any | Details for pii_shield_llm-1.0.2-py3-none-any.whl |
Total release size: 34.7 kB
Release files / pii_shield_llm-1.0.2.tar.gz
| Download URL | pii_shield_llm-1.0.2.tar.gz |
|---|---|
| Size | 18.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
79cac0730680a438ac186c795d8444c0ce0dbc97ea97e8be43bb0d2c818a3a1a
|
|
BLAKE2b-256 checksum How to use checksums |
8c5b6914ac5e9021a3663ed8ad3cb7e3cd4760bac8241c021e6c75fcc0396f06
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 14, 2026.
Transparency logRelease files / pii_shield_llm-1.0.2-py3-none-any.whl
| Download URL | pii_shield_llm-1.0.2-py3-none-any.whl |
|---|---|
| Size | 16.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9feceaa77773a0ccbe2d0a5152d4217240c3e1d39d83f864d848513c3aaa6605
|
|
BLAKE2b-256 checksum How to use checksums |
95a2f6f7a04255e19f6cd6ad4384609b9207be92ec72a285bea500de3607b31c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 14, 2026.
Transparency logSecurity for pii-shield-llm 1.0.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for pii_shield_llm-1.0.2.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 14, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.