MaskGuard
AI-powered PII discovery and query-time, role-based masking for PostgreSQL, MySQL and SQLite.
MaskGuard is a gateway between people and the database. It finds sensitive columns by looking at their values (a LightGBM classifier plus checksum validators for Aadhaar, PAN, GSTIN, cards, IBAN and more). It rewrites every query so the database itself returns only what the caller's role may see. It watches for probing, and records every decision in a hash-chained audit log. Stored data never changes.
| Role | Sees |
|---|---|
| Admin | real values |
| Support | partial masks: 4111-XXXX-XXXX-1111, XXX-XX-6789, r***@bank.in, rounded balances |
| Analyst | keyed tokens (joinable, not reversible); no individual balances |
| Auditor | REDACTED, plus the audit log, policies and integrity proofs |
Install and try it
pip install maskguard
export MASKGUARD_HMAC_KEY=dev-only-hmac-key-change-me # PowerShell: $env:MASKGUARD_HMAC_KEY="..." cmd: set MASKGUARD_HMAC_KEY=...
maskguard # console with synthetic demo data (created in ./data/)
maskguard compare "SELECT name, ssn, phone FROM users LIMIT 2" --roles admin,support,analyst,auditor
maskguard serve # REST API + Control Room at http://127.0.0.1:8000/ui/
Demo logins: admin.ann, support.sam, analyst.ali and auditor.aud, each with password <role>123. Data,
the audit log and the scanner registry are written to ./data/ in the folder you run it from.
maskguard status shows HMAC KEY FAIL until you set the key: there is deliberately no default key. If it shows
PII SCANNER WARN … rules only, the system lacks the OpenMP runtime the ML scanner needs: install libgomp1
(Debian/Ubuntu, including python:*-slim images) or libomp (macOS, with Homebrew).
To use your own database, set MASKGUARD_DB (postgresql://… or mysql://…) and MASKGUARD_DEMO=0. Columns
the scanner finds nothing in are UNREVIEWED and masked for every role except admin until you approve them as
PUBLIC in your overrides file (maskguard pii list shows them). For real data, run in production mode
(MASKGUARD_ENV=production): it refuses to start on any unsafe setting.
Results
- PII discovery: 0.965 F1 with misleading column names and 5 sample values per column; the benchmark baseline scores 0.844.
- Attack suite: 0 of the 17 bypass and inference attacks in its suite leak, against 14–15 of 17 for output-only masking. That is evidence for those attack shapes, not a proof for every query.
- Tests: 500 tests on SQLite, PostgreSQL 16 and MySQL 8.4.
- Latency: about 8 ms added per query.
What's new in 1.0.2
- The rule-based scanner now finds identifiers inside free text. It is the fallback when LightGBM can't load. In
1.0.1 it missed them, so such a column stayed masked as
UNREVIEWEDinstead of being tagged. maskguard statuswarns (WARN, exit code unchanged) when the scanner runs on rules only, and says what to install;maskguard doctorno longer fails on it.
What's new in 1.0.1
Security fixes from an external source audit:
- Unreviewed columns fail closed. In 1.0.0 a column the scanner found nothing in was returned to every role
unmasked. It is now
UNREVIEWED(admin only) until a person approves it asPUBLIC. - SQL comments and MySQL optimizer hints no longer reach the audit log or the database.
- Database error text no longer reaches clients through the PostgreSQL proxy or the classic dashboard.
- The
querycapability is enforced on every path.
Upgrade with pip install -U maskguard. On your own database, review the UNREVIEWED columns after upgrading.
Learn more
- README and screenshots
- Beginner's guide: every term, with diagrams and step-by-step workflows
- Deployment guide
- 8-minute walkthrough video
Noisy analyst aggregates are experimental and refused in production until an independent privacy review. Licensed under Apache-2.0.
Metadata
Release files for maskguard 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 | |
|---|---|---|---|
| maskguard-1.0.2.tar.gz | 23.4 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| maskguard-1.0.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 24.1 MB
Release files / maskguard-1.0.2.tar.gz
| Download URL | maskguard-1.0.2.tar.gz |
|---|---|
| Size | 23.4 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f11ce49a1f7022ed89eef19b32fe1085b01aec02af3cc04b9a56f70c81da9426
|
|
BLAKE2b-256 checksum How to use checksums |
2c1eea1a1ac48f857886706ed0ef770ba698a59bb8339b1e90c7e3315bae13d8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Oct 18, 2026.
Transparency logRelease files / maskguard-1.0.2-py3-none-any.whl
| Download URL | maskguard-1.0.2-py3-none-any.whl |
|---|---|
| Size | 697.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e01866a7d1dcaecdef79c6aaaae4e59246f346d43ce6a2c9bed92da3f9007219
|
|
BLAKE2b-256 checksum How to use checksums |
0f5d3e56b34b172c979c4545fc23db234d10eaeadf8095cafade23c590ca0674
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Oct 18, 2026.
Transparency log