DAAM
Alpha

Data Masking

Data masking transforms sensitive column values in SELECT results before they reach the developer. Masking is column-level and read-side only — writes (INSERT, UPDATE) pass through unaffected. Masking is orthogonal to table grants: a user with SELECT on a table sees masked values for any masked columns, while a user without SELECT cannot query the table at all.

Overview

Masking rules are defined as part of policies. Each rule maps a column match pattern to a masking preset. When a query result includes a matched column, the agent replaces the raw value with a masked version before forwarding it to the client.

  • Column-level — masking targets individual columns, not entire rows or tables.
  • Read-side only — INSERT and UPDATE statements pass through unaffected. Only SELECT results are masked.
  • Transparent — developers see masked values in their query results without any changes to their queries or client code.
  • Policy-driven — masking rules are configured in the console as part of a policy and pushed to agents automatically.

Masking never prevents access to a table. To control which tables a user can query, use table grants. Masking controls what the user sees in the columns they are allowed to read.

Masking Presets

DAAM provides seven built-in masking presets. Each preset is designed for a specific data type and preserves enough structure to confirm the data format while hiding the sensitive content.

PresetInputOutputWhat Leaks
email[email protected]j***@e***.comFirst char of local part, first char of domain, TLD
phone415-555-1234***-***-1234Last 4 digits
ssn123-45-6789***-**-6789Last 4 digits
credit_card4111-1111-1111-1111****-****-****-1111Last 4 digits
nameAlice JohnsonA*** J***First character of each word
redactanything***Nothing — full redaction
nullanythingNULLNothing — value replaced with SQL NULL

Masked values are returned as strings regardless of the original column type.

If the original column value is NULL, it passes through unchanged. NULL is already the absence of data, so no masking is needed.

Adding Masking Rules

Masking rules are configured as part of a policy in the console. To add a masking rule:

  1. Navigate to the database and open the policy you want to edit.
  2. In the Masking Rules section, click Add Rule.
  3. Enter a match pattern (e.g. public.users.email) or use the column dropdown to select from discovered columns.
  4. Choose a masking preset from the dropdown.
  5. Save the policy.

The column dropdown is populated from the agent's schema introspection. The agent automatically discovers your database's tables and columns and reports them to the control plane, so the dropdown always reflects your actual schema.

Once saved, the updated policy is pushed to the agent immediately. New masking rules take effect on subsequent queries — there is no delay or restart required.

You can also type wildcard patterns directly into the match pattern field. Wildcards are useful for applying the same masking preset across multiple tables or schemas without creating a rule for each column individually.

The masking rules editor below shows five rules using different presets. Click a column pattern field to open the searchable dropdown populated from schema introspection data.

Interactive preview

Masking Rules

Standard masking transforms query output — developers see masked values but can reference the column freely in SQL.

Strict masking additionally blocks the column from being used in WHERE, GROUP BY, JOIN, HAVING, and other query clauses. This prevents inference attacks where a developer could deduce masked values through query predicates.

Strict-masked columns can only appear in SELECT output, ORDER BY, and RETURNING clauses.

Pattern (schema.table.column)TypeStrict

Match Patterns

Masking rules use three-part match patterns in the format schema.table.column. Each segment can be a literal name or a wildcard (*). Matching is case-sensitive.

PatternMatches
public.users.emailThe email column on the users table in the public schema
public.users.*All columns on the users table in the public schema
public.*.emailAny column named email in any table in the public schema
*.users.emailThe email column on the users table in any schema
*.*.emailAny column named email in any table in any schema
*.*.*Every column in every table (use with caution)

Wildcard patterns let you enforce masking broadly. For example, *.*.email with the email preset ensures that any column named "email" is masked across all tables, including tables added in the future.

Pattern Specificity

When multiple masking rules within a single policy match the same column, more specific patterns override wildcards. For example, public.users.email takes priority over *.*.email when resolving the public.users.email column, while the wildcard still applies to email columns in all other tables.

Overlapping Policies

When a user is assigned to multiple policies on the same database and those policies define masking rules for the same column, the most restrictive preset wins. This ensures that sensitive data is never exposed through a less-restrictive policy.

For example, if one policy shows a column unmasked and another redacts it, the column is redacted. The null and redact presets are the most restrictive since they reveal the least information.

If a masking rule exists in one policy but not another, the rule is included in the effective policy. The absence of a masking rule in one policy does not cancel a rule from another.

Example: Policy A masks public.customers.email with the "email" preset. Policy B masks the same column with "redact". A user assigned to both policies sees public.customers.email masked with "redact" because it is more restrictive (rank 2 vs rank 4).

Computed Columns and Aliases

Masking works with aliased columns. If you write SELECT email AS e FROM users, DAAM resolves the original column name from the database metadata and applies masking rules that match public.users.email, not the alias.

For computed columns (expressions, aggregates, literals), the agent cannot resolve a physical column identity. Only wildcard rules that match the alias name apply. For example, *.*.cnt would match SELECT COUNT(*) AS cnt, but public.users.cnt would not.

Validation

The following rules are enforced when saving masking rules in a policy:

  • Match patterns must have exactly three dot-separated segments (schema.table.column).
  • Each segment must be a valid name or the wildcard *.
  • The masking type must be a known preset (email, phone, ssn, credit_card, name, redact, or null).
  • No duplicate match patterns within the same policy.

Invalid masking rules are rejected on save with an error message indicating which rule failed validation.