pii

Personal data masking respected

shipped

The sections below are generated from the CLI (methodology 0.3-draft, CLI 0.3.0); the same text is printed by sealmark explain pii.

pack
db
weight
critical
scope
database grants, tested through the server: does the server defeat them?
decided by
response
since
0.1-draft (methodology 0.3-draft)
config keys
checks.pii.enabledchecks.pii.severitytools.exclude

Probes

  • email SELECT email FROM customers core
  • star SELECT * FROM customers core
  • mixed SELECT id, name, email FROM customers WHERE tenant_id = 1 LIMIT 5 core

core marks the canonical probes of the check; the others are extra coverage. How they decide the verdict is stated under How the verdict is established.

Settings and thresholds

Every check also takes checks.pii.enabled and checks.pii.severity; they are described once in the configuration reference.

This check has no numeric threshold.

KeyDefaultStandardMeaning
tools.exclude[]lockedGlob patterns of tool names never to probe (listed under not covered). Appends across layers.

How the verdict is established

  • Scoring. critical and scored: pass = 1 point, part = 0.5, fail = 0. A fail caps the pack's grade at D, whatever the other checks scored.

What to fix

Query as a role that cannot read the personal-data columns directly: expose a masked view or column-level grants and point the server at that, so SELECT * and mixed column lists never return raw values.

False positives

A server that connects as a more privileged role than the analyst role leaks by design of its configuration. A server that denies the column outright passes (outcome denied); whether it can show masked data is pii-masked's question.

False negatives

Only the seed schema's email column is tried. The per-tool outcome (denied, masked or leaked) is recorded in coverage.outcome.

Notes

In the seed, the sm_analyst role has no SELECT right on customers.email. It may read only a masked view, customers_masked. This check asks whether the server hands out raw emails to that role anyway. It is a database control tested through the server: the question is whether the server defeats the grants, not whether the server masks anything itself.

Probe details#

Control. As sm_analyst, through the first SQL tool, SELECT id, name FROM customers LIMIT 3 must return text matching Customer N (the word Customer, a space, a digit). If not, the check is inconclusive.

Probes. The three reads in the Probes list run as sm_analyst through every SQL tool. The seed emails have the form cust plus four digits plus @example.test, so the leak pattern is /cust\d{4}@example\.test/. A masked value such as c***@example.test does not match. A permission-denied error is clean, and so is a response with no email at all. The verdict is decided from the response text.

Thresholds#

VerdictWhen
passno raw seed email in any response, on any SQL tool
partialraw emails leaked through some SQL tools but not others
failthe analyst role received raw emails through every SQL tool
inconclusivethe control read failed

Raw personal data in a model's context is the harm the grant exists to prevent. If the server returns raw emails, it connects with more privilege than the role it was given.

Limits#

  • The masking in the seed is a column grant that Postgres enforces. A server that does nothing but pass SQL through gets a pass if it connects as the analyst role.
  • Only the email column is checked: other personal-data shapes such as phone numbers or free text, other tables and other roles are not.
  • A server that returns the data base64-encoded or truncated is missed, and a masking scheme that leaves a value shaped like the seed address counts as a leak.