Skip to content

Repository files navigation

English | Русский

SafeGate

Self-hosted AI security platform for LLM applications

Protect sensitive data · Stop prompt attacks · Control inference cost · Audit everything

Python 3.10+ License: MIT CI Version

Features · Quick start · What we detect · Examples · How it works · Docs

pip install safegate


Features

SafeGate sits between your app and the LLM (and around RAG embeddings). You enable only the stages you need.

Capability What you get How to use
PII / secrets detection 60+ entity types across identity, finance, health, network, vehicles, RU/US/UK IDs SafeGate() / entity_types=[...]
Substitution or mask Prompt: replace with dictionary fakes, or ***. Response: always *** (never fake values to the user) protection_mode="substitute" / "mask"
Prompt & response guards Protect text before the LLM call; scan the answer for leaks; mask residual PII in the reply protect_promptinvokeprotect_response
Choose what to detect Enable only the sensitive types you care about; everything else is ignored entity_types=["email", "ssn", …]
EDOS guard (optional) Score “cognitive bomb” prompts; strip wasteful instructions, route to a fallback LLM, or block edos_enabled, edos_high_risk_action
Vector privacy (RAG) ε-differential privacy noise + lineage obfuscation for embeddings VectorPrivacyGuard / ContextGuard
Policies & industry packs YAML rules, presets (health_hipaa, bank_ru, …), simulator preset="…", safegate policy catalog
Audit & SIEM JSONL trail, CEF/ECS/CSV export, approval workflow audit_path=…
Prompt  →  PII guard  →  EDOS*  →  your LLM  →  response guard  →  user
RAG     →  context guard  →  vector privacy*  →  vector DB

* optional stages

Quick start

Install

pip install safegate

1) Protect text (no LLM required)

from safegate import SafeGate

guard = SafeGate(protection_mode="substitute")  # or "mask"
session = guard.protect_prompt(
    "Contact Alice at alice@company.com or +1 (415) 555-0100"
)
print(session.prompt_result.text)
# Contact … at <dictionary email> or <dictionary phone>
print(session.prompt_mappings)

2) Detect only selected types

from safegate import SafeGate, list_entity_types

# only email + phone + SSN
guard = SafeGate(entity_types=["email", "phone", "ssn"])

# or a whole domain
guard = SafeGate(entity_types=list_entity_types("financial"))

Full catalog: docs/SENSITIVE_ATTRIBUTES.md
CLI: safegate entities list --domains

3) Wire your real LLM

from safegate import SafeGate
from safegate.llm import OpenAIAdapter  # or OllamaAdapter

guard = SafeGate(protection_mode="substitute")
session = (
    guard.protect_prompt("My SSN is 123-45-6789")
    .invoke(OpenAIAdapter(client, model="gpt-4o-mini"))
    .protect_response()
)
print(session.result)

OpenAIAdapter works with any OpenAI-compatible API. OllamaAdapter is for local models.

About MockLLM: it is a tiny stub that returns a fixed string. SafeGate uses it only in unit tests and offline demos so CI does not need API keys. It is not a production model — pass your own adapter to invoke() / chat().

4) Optional: EDOS cost protection

guard = SafeGate(
    edos_enabled=True,                          # set False to skip the stage
    edos_high_risk_action="block",              # or "route_fallback"
    fallback_llm=OpenAIAdapter(cheap_client, model="gpt-4o-mini"),
)

5) Optional: RAG embedding privacy

from safegate import VectorPrivacyGuard
from safegate.guards import ContextChunk, ContextGuard

vector_guard = VectorPrivacyGuard(epsilon=1.0)
ctx = ContextGuard(vector_privacy=vector_guard)
result = ctx.protect_embeddings(
    [ContextChunk(id="doc-1", text=text, embedding=vector)]
)

What we detect

Entities are grouped into domains. Enable a domain or pick individual types.

Domain Types (examples)
identity full_name, date_of_birth, passport, us_passport, driver licenses
contact email, phone, address, zip_code
national_ids ssn, nino (UK), inn/snils (RU), ein, itin, employee_id
financial credit_card, cvv, card_expiration, iban, swift_bic, salary, bank accounts
health medical, member_id, insurance_id, npi, medicare_id
credentials password, username, api_key
network ip_address, mac_address, domain, social_handle (LinkedIn, @handles)
vehicles vin, vehicle_registration, ru_license_plate, frequent_flyer
business commercial_secret
attacks prompt_injection, jailbreak (ThreatFeed)
safegate entities list --domains

Complete tables with examples: docs/SENSITIVE_ATTRIBUTES.md


Examples

Sensitive values are found first, then either substituted from a built-in dictionary (prompt path) or masked with * (mask mode, and always on the LLM response).

PII detectors highlighting sensitive fields

Mode A — Dictionary substitution (prompt → LLM)

Fake values come from generated dictionary pools shipped with SafeGate (gdpr_fakes, default, industry packs). The vault maps each real value → one synthetic token for the session, so the LLM still sees realistic emails, phones, and IDs — not your real data.

guard = SafeGate(protection_mode="substitute")
# michael.carter@example.com  →  sofia.brennan@privacy.test   (from dictionary)
# +1 (415) 555-0187           →  +49 30 4829173               (from dictionary)

Prompt Guard substitutions from dictionary

Mode B — Mask with asterisks

guard = SafeGate(protection_mode="mask")
# michael.carter@example.com  →  **************************

Prompt Guard masking with asterisks

LLM response — always masked

Whatever comes back from the model is never filled with dictionary fakes and is never restored to real PII by default. Residual PII and echoed substitute tokens are replaced with *. Opt-in detokenize=True restores real values only when you explicitly need that legacy behaviour.

Prompt sent to the LLM after masking

Direction Substitute mode Mask mode
Prompt → LLM Dictionary fakes ****
LLM → user **** (always) **** (always)

Local UI to try both modes:

cd local-demo && python app.py
# http://127.0.0.1:8765/

How it works

flowchart LR
    A[Input] --> B[Detectors — optional entity filter]
    B --> C[Policy]
    C -->|substitute / mask / block| D[Prompt guard]
    D --> E[EDOS optional]
    E --> F[Your LLM]
    F --> G[Response guard — always mask]
    G --> H[Output]
Loading
Stage Role
Detectors Find sensitive values (filtered by entity_types if set)
Policy Decide action per type: substitute · mask · block · remove
Prompt guard Apply policy before the LLM call (dictionary or ****)
EDOS Optional complexity scoring / strip / route / block
Response guard Leak check; always mask residual PII and echoed tokens with ****
Audit JSONL + SIEM fields including EDOS

Examples

Example Use case
chatbot_demo.py Chatbot with PII substitution
rag_demo.py RAG context guard
mcp_demo.py MCP tool filter
gateway_client.py REST AI gateway
langchain_demo.py LangChain handler

Full list: examples/README.md


Industry packs

bank_ru · health_hipaa · gov_fz152 · retail_eu · fintech_us · insurance_us · saas_global · telecom_eu · education_us · energy_eu · legal_eu · logistics_eu

safegate policy catalog --format markdown
guard = SafeGate(preset="health_hipaa", region="us")

Documentation

Doc Contents
SENSITIVE_ATTRIBUTES.md Full entity catalog + how to select types
INSTALL.md Install / Docker
COMPARISON.md vs Presidio / LLM Guard
PRODUCT_ROADMAP.md Platform roadmap

Contributing

SafeGate is open source (MIT).

git clone https://github.com/patonkikh/SafeGate.git
cd SafeGate
python -m pip install -e ".[dev]"
pytest -v
Issues github.com/patonkikh/SafeGate/issues
Guidelines CONTRIBUTING.md
Security SECURITY.md

License

MIT

About

Self-hosted security layer for LLM apps: PII substitution, prompt/response guards, EDOS & vector privacy. pip install safegate

Topics

Resources

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages