Skip to main content

Runtime PII leak detector for Django — find personal data leaking from your API responses and third-party calls

Project description

Wiregraph

What sensitive user data is leaving your Django app — and where is it going?

Most teams can't answer that. Your view returns more than you think. Your OpenAI call ships customer emails to a third party. Your Stripe webhook echoes an SSN into a log line. Static analysis won't catch it. APM won't flag it.

Wiregraph is a runtime PII leak detector that sits inside your Django app and watches the traffic you're actually serving.

Wiregraph dashboard — live PII flow map

React dashboard — coming soon. The screenshot above previews the standalone React dashboard (currently in development). The bundled Django admin dashboard at /admin/wiregraph/dashboard/ ships today.

The alarm moment

A user hits /api/v1/support/ticket/. Your view enriches the response with an OpenAI summary. Wiregraph sees this:

[egress] POST api.openai.com/v1/chat/completions
  └─ EMAIL_ADDRESS  (confidence 0.99)  asset: request.body.messages[1].content
  └─ US_SSN         (confidence 0.95)  asset: request.body.messages[1].content

[response] 200 /api/v1/support/ticket/
  └─ PHONE_NUMBER   (confidence 0.90)  asset: response.body.ticket.notes

You didn't write code to log that. You didn't know it was happening. Now you do.

What you get

  • Runtime visibility into every PII-bearing field crossing your app's boundary — inbound, outbound, egress
  • Audit trail of which endpoints leak what, by tenant
  • Compliance evidence — exportable PDF/JSON reports of observed flows
  • Zero raw PII at rest — detections are hashed, masked, or truncated before storage

APM tells you a request was slow. Logs tell you what you decided to log. Wiregraph tells you what your app actually sent.

Quick start

1. Install and configure

pip install wiregraph
# settings.py
import wiregraph

INSTALLED_APPS = [*INSTALLED_APPS, *wiregraph.INSTALLED_APPS]
MIDDLEWARE = wiregraph.setup(MIDDLEWARE)
WIREGRAPH = {"ENABLED": True}

Install and configure

2. Migrate and attach a superuser to a tenant

python manage.py migrate
python manage.py wiregraph_doctor   # sanity-check config

# create a superuser if you don't already have one
export DJANGO_SUPERUSER_PASSWORD=admin
python manage.py createsuperuser --noinput --username admin --email a@a.com

# attach your admin user to a tenant so events get attributed
python manage.py shell -c "from django.contrib.auth import get_user_model; from wiregraph_apps.tenants.models import Tenant, TenantMembership; u = get_user_model().objects.filter(is_superuser=True).first(); t, _ = Tenant.objects.get_or_create(name='Demo Co', defaults={'slug': 'demo'}); TenantMembership.objects.get_or_create(user=u, tenant=t)"

Migrate and create tenant

3. Hit an endpoint and watch the leak

Hit any endpoint, then open /admin/wiregraph/dashboard/ to see the flow graph. (For the JSON API at /api/v1/, install wiregraph[drf] — see below.)

PII leak in the dashboard

Wiregraph skips the Django admin URL prefix by default — otherwise the DataEvent admin would re-detect its own contents on refresh. Override with AUTO_EXCLUDE_ADMIN=False.

Install extras

Wiregraph ships in slices so you only pull in what you need.

Install line What you get
pip install wiregraph Core middleware + bundled admin dashboard at /admin/wiregraph/dashboard/. No DRF.
pip install wiregraph[drf] Adds the JSON API at /api/v1/ (viewsets, JWT auth, OpenAPI schema). Required by the React wiregraph-dashboard consumer.
pip install wiregraph[presidio] ML-based detection. Also run python -m spacy download en_core_web_lg.
pip install wiregraph[export] PDF/JSON compliance reports.
pip install wiregraph[postgres] psycopg[binary] for Postgres backends.
pip install wiregraph[all] Everything above plus dev tooling.

If you skip [drf], the /api/v1/ routes are not registered — the admin dashboard still works.

Security guarantee

Wiregraph never persists raw PII. Every detection is redacted (hash / mask / truncate, configurable) before it touches storage. The matched value lives in memory only long enough to classify and redact.

Detection

Regex out of the box: emails, phones, SSNs, credit cards, and more. Add your own:

WIREGRAPH = {
    "ENABLED": True,
    "CUSTOM_PATTERNS": [
        {"name": "emp_id", "regex": r"\bEMP-\d{6}\b", "confidence": 0.9},
    ],
}

Optional Presidio (ML NER for names, addresses, IBANs, 50+ entity types) runs async via Celery so the request path stays fast:

WIREGRAPH = {"ENABLED": True, "ENABLE_PRESIDIO": True}

See Installing Presidio. Presidio matches that overlap a regex hit on the same asset are deduped (regex wins).

Classification

Not every PII hit is a leak. An email to api.stripe.com is the product working; the same email to api.openai.com is an incident. Wiregraph classifies every DataEvent on what × where × policy and writes the verdict to DataEvent.outcome:

Outcome Meaning
expected Asset flowed to a sink that accepts it (Stripe ← email)
acceptable Trusted sink, asset not on its accept-list but not dangerous
suspicious Unknown sink, new flow, or known sink receiving an unexpected asset
prohibited Sensitive asset to a sink that should never receive it

A built-in catalog (~15 vendors: Stripe, OpenAI, Anthropic, Bedrock, Twilio, SendGrid, Segment, S3, Auth0, …) means a fresh install gets meaningful outcomes with zero setup. Override per-host via SINK_OVERRIDES (settings) or SinkCatalogOverride (DB, tenant-scoped). LLM strictness is tunable: LLM_POLICY = "strict" (default — medium+ PII to LLM is prohibited) or "relaxed".

Tenant resolution

By default Wiregraph walks request.user.tenant_memberships. Point TENANT_RESOLVER at your own callable if your project stores tenancy differently (FK, subdomain, header).

Retention purge

Delete events older than DATA_RETENTION_DAYS:

python manage.py wiregraph_purge [--dry-run]

Or via Celery Beat:

import wiregraph.celery as wg_celery
CELERY_BEAT_SCHEDULE = {**wg_celery.schedule(hour=3, minute=0)}

API

Requires pip install wiregraph[drf]. Without the extra, /api/v1/ routes are not registered.

Versioned under /api/v1/, JWT Bearer auth (obtain via /api/v1/auth/token/). OpenAPI at /api/v1/schema/, Swagger at /api/v1/schema/docs/.

Method Path Description
POST /api/v1/auth/token/ Obtain access + refresh token
POST /api/v1/auth/token/refresh/ Rotate refresh token
GET /api/v1/detection/events/ List events (filter: direction, data_asset, endpoint, timestamp__gte, timestamp__lte)
GET /api/v1/detection/events/{id}/ Retrieve event
GET /api/v1/detection/assets/ PII categories seen in traffic
GET /api/v1/detection/stats/summary/ Dashboard counts

See docs/settings.md for all config keys.

Requirements

Python ≥ 3.10 · Django ≥ 4.2 · Celery + Redis (async detection) · PostgreSQL recommended

License

MIT

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

wiregraph-0.1.0.post2.tar.gz (67.2 kB view details)

Uploaded Source

Built Distribution

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

wiregraph-0.1.0.post2-py3-none-any.whl (106.7 kB view details)

Uploaded Python 3

File details

Details for the file wiregraph-0.1.0.post2.tar.gz.

File metadata

  • Download URL: wiregraph-0.1.0.post2.tar.gz
  • Upload date:
  • Size: 67.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for wiregraph-0.1.0.post2.tar.gz
Algorithm Hash digest
SHA256 6833818d1c7e8268cf9e37d669bf6a15db835386206a2501c40ae59c593833dd
MD5 be41f7da9dba61faf97262c12f36ee2e
BLAKE2b-256 66c80aa64055cf373e03fc110e0f2d2a13189a36249ffcaf0012f167893ab073

See more details on using hashes here.

File details

Details for the file wiregraph-0.1.0.post2-py3-none-any.whl.

File metadata

File hashes

Hashes for wiregraph-0.1.0.post2-py3-none-any.whl
Algorithm Hash digest
SHA256 c0ebfb165f6d6df755fc00cad3f5ba0859a69dce50e71abca248f60d67a567d7
MD5 1554ba1f23a434d0bf7818316e58bdf9
BLAKE2b-256 c1f8938321ecef61d9b00c1d4fc94b4bc9cb8d57f313f6aff9bb073d19b6c517

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