Skip to main content
A query runs against real production data and returns real production data. Data Masking sits on the way back: the Sidecar decodes the response as it streams, finds sensitive values, and rewrites them before the client ever sees them. Nothing is copied, staged or transformed at rest. The masking happens in memory, in real time, at the protocol layer — so it works the same for psql, for an ORM, for a dashboard and for an agent.
Masking runs on responses only. Requests are never rewritten: changing the statement the upstream executes is a correctness change wearing a privacy label.
Free tier: one Data Masking rule and one Guardrail per Sidecar are free, forever. Running more than one rule per feature, or managing rules centrally across Sidecars, requires Enterprise.

Configuration

Two blocks, and both are required. pii turns detection on; mask says what to do with what was detected.
config.yaml
The same query now comes back rewritten:
pii.entities is required and there is no all-entities default. A mask rule naming an entity that detection was never told to look for loads cleanly, evaluates, and masks nothing — the config looks live while everything leaks. Name the types your data actually contains.The opposite is also a real cost: turning on every recognizer rewrites ordinary numeric columns, because nine digits in a legal range is a valid US_SSN as far as any detector can tell.

Rule fields

Strategies

hash is the one worth knowing about: equal inputs give equal outputs, so a masked column still works as a join key. An analyst can group by customer without ever seeing a customer.

Entity rules and column rules

Two ways to name what gets masked, and they fail in opposite directions. Entity rules mask by detection. They work anywhere a value appears, including inside an opaque HTTP body where the protocol names nothing — and they miss whatever the detector does not recognize. Column rules mask by position. They cannot miss, because they never guess — and they only work where the protocol names its values, which means result sets, not payloads.
Use column rules for the columns you know, and entity rules for everything else.

Inheritance: a listener’s mask block replaces the defaults

This is the single most common way a working config quietly stops masking:
config.yaml
A listener’s mask block replaces the top-level list rather than extending it. Adding one column rule drops every inherited entity rule, so list those again alongside it. This is deliberate: a rule owns an entity type, and two concatenated lists would leave two rules competing for one entity. policy.rules behaves the opposite way — it concatenates.

Verify what actually resolved

The admin API reports the resolved state per listener, which is the only place the merge above is visible:
If a value comes back unmasked, the detector probably refused it rather than missed it — obvious test fixtures like 123-45-6789 are deliberately not reported. Add a column rule, or widen pii.entities.

Looking for masking on the Hoop Gateway instead? That is a different implementation, configured in the web app with DLP providers and per-resource roles. See Live Data Masking.

Next

Guardrails

Control what reaches the resource, not just what comes back.

Config File Reference

Every field, the full entity list, and what startup refuses.