> ## Documentation Index
> Fetch the complete documentation index at: https://warden.buildlab.in/llms.txt
> Use this file to discover all available pages before exploring further.

# Masking

> Keep customer data out of a model's context, without making the agent useless.

Rows an agent reads become text in a model's context. Masking decides which values it may see.

```yaml theme={null}
masking:
  customers.email: tokenize
  customers.phone: partial
  payments.card_number: redact
```

| Mode | Result | Use it when |
| - | - | - |
| `redact` | A fixed marker | The agent never needs the value |
| `hash` | A deterministic digest | Equality matters, the value does not |
| `tokenize` | A deterministic token that round-trips | The agent must *refer* to the value later |
| `partial` | A recognisable fragment | A human reads the output and needs to recognise the record |

Tokenization is the one that keeps agents useful: `alice@example.com` always becomes the same `tok_…`, so the agent can group, join, and refer to it — and can hand the token back to Warden in a later operation — without the address ever entering its context.

## Masked inside the statement

Masking applied to result rows is defeated by one expression:

```sql theme={null}
SELECT upper(email) FROM customers;   -- not the column, so not masked
SELECT c.email AS contact FROM customers c;  -- renamed, so not matched
```

So where the engine allows it, masking happens **inside** the statement. Each governed table is replaced by a subquery in which the column is already masked, and the agent's own SQL can only reach the masked value — through an alias, a function, a join, or anything else it writes. The certification suite attacks exactly these paths.

Masking keys come from `masking_salt`, so tokens are stable across restarts and consistent everywhere the same value appears. Treat the salt as a secret: it is what stops a token being reversed by someone who can guess likely inputs.

## Failure discards the result

> [!WARNING]
>
> If a masking rule cannot be applied, **the entire result set is discarded** and the operation returns `masking_failed`. Returning partially masked rows would leak precisely the values the rule exists to protect.

## Column restriction is separate

```yaml theme={null}
- { kind: table, path: [shop, customers], columns: [id, tenant_id, email, tier] }
```

Masking transforms a value the agent may see. Column restriction means the column is not in the projection at all — `SELECT *` returns the permitted columns, and naming an unpermitted one is refused. Use restriction for columns the agent has no business reading, and masking for ones it needs to work with but must not read.

## What masking is not

It is not encryption, and it is not a substitute for not storing the data. A determined agent that can read enough masked values and correlate them with data it already has can sometimes infer the original. Masking raises the cost and removes the accident — an agent pasting a customer list into a prompt — which is the realistic threat.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.