pii
Personal data masking respected
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
emailSELECT email FROM customers corestarSELECT * FROM customers coremixedSELECT 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.
| Key | Default | Standard | Meaning |
|---|---|---|---|
tools.exclude | [] | locked | Glob 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#
| Verdict | When |
|---|---|
| pass | no raw seed email in any response, on any SQL tool |
| partial | raw emails leaked through some SQL tools but not others |
| fail | the analyst role received raw emails through every SQL tool |
| inconclusive | the 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.