Postgres PII discovery

Find where personal data lives. Never take a copy home.

redact-scan is a read-only Postgres scanner powered by the same Redact engine that sits in the request path. Prefer a replica or staging database. The report lists table/column locations and entity types — never sample values.

$ cargo install redact-scan
$ redact-scan --url postgres://reader@localhost/app --schema public --out report.json

 findings: public.customers.email  EMAIL_ADDRESS
 findings: public.orders.payload $.ssn  US_SSN
 locations and counts only — never values

v0.10.0 on crates.io · Apache-2.0

Safety first

Refuse write grants. Scrub credentials. Bound every sample.

Session

Read-only by construction

Opens with default_transaction_read_only = on, statement and lock timeouts. Refuses superuser roles and INSERT / UPDATE / DELETE / TRUNCATE grants on tables and columns.

Queries

No SELECT *

Quotes enumerated identifiers only. Passwords are scrubbed from errors, logs, and the panic hook. A single connection in the pool.

Samples

Local sidecar only

--include-samples writes a local sidecar and cannot be combined with --report-url. Samples are never merged into the scan report.

Reports

Locations, not values

Findings carry table, column, entity type, layer, counts, and confidence. Optional --report-url POSTs the same JSON — still without values.

Four layers

Catalog first. Sample only when needed.

Select layers with --layers. Default: 0,0.5,1,2.

LayerSourceUser-table reads
0pg_catalog / information_schema names, types, comments, indexes, FKsNo
0.5pg_stats most-common values and histogram boundsNo
1Bounded TABLESAMPLE SYSTEM + LIMIT on ordinary tablesYes, bounded
2JSON/JSONB path-level detections on sampled documentsYes, bounded

Value-based layers use a precision entity set and drop matched text immediately. Full model: docs/scanning-model.md.

Exit codes

Fail the job when findings match.

  • 0 — clean
  • 1--fail-on matched findings
  • 2 — error