Masking¶
Once a value is detected, three settings shape what replaces it:
- the operator decides what the value becomes and whether it can be restored;
- the token format decides how a placeholder is written;
- the anchor decides whether the same value gets the same placeholder in every session.
Operators¶
operator.type |
alice@example.com becomes |
Restored in replies | Vault stores | Needs |
|---|---|---|---|---|
pseudonym (default) |
<PRIVYX_EMAIL_1> |
Yes | The original | Nothing |
hash |
<PRIVYX_EMAIL_ff8d9819fc0e> |
Yes | The original | Nothing |
encrypt |
<PRIVYX_EMAIL_AAE5ECF9F12ED145> |
Yes | Ciphertext only | privyx[crypto] and a key |
faker |
curtisjohnson@cummings.net |
Yes | The original | privyx[faker] |
redact |
[REDACTED] |
No | Nothing to restore | Nothing |
pseudonym¶
Replaces each value with a numbered token. Within a session, the same value always gets the same token. This is the default and the right choice unless you need one of the properties below.
hash¶
The token's id is a SHA-256 digest of the value, cut to length hex
characters (default 12). The same value gets the same token in every
session, without a secret.
operator:
type: hash
length: 12
A short unkeyed hash can be matched by anyone who guesses the value. Prefer
pseudonym with an anchor when that matters.
encrypt¶
The vault stores AES-256-GCM ciphertext instead of the original value, so a leaked or shared vault exposes no personal data. The token's id is a keyed digest of the value.
pip install 'privyx[crypto]'
export PRIVYX_ENCRYPT_KEY=$(openssl rand -hex 32)
operator:
type: encrypt # key from PRIVYX_ENCRYPT_KEY, or `key:` here
Without the package or the key, Privyx fails at startup. Losing the key means the stored sessions can no longer be restored. See Cryptography.
faker¶
Replaces a value with a realistic fake of the same kind, so the model reads a plausible email or name rather than a placeholder.
operator:
type: faker
locale: en_US # optional
seed: 1234 # optional: the same value fakes the same way across runs
Fakes are restored by matching the exact fake strings. If the model happens to
write one of them on its own, it is restored too. Use pseudonym when exact
reversal matters more than realism.
redact¶
Replaces the value with fixed text and keeps nothing, so the reply cannot get it back:
operator:
type: redact
token: "[REDACTED]"
Token format¶
The token operators (pseudonym, hash, encrypt) write placeholders from
token.format:
token:
namespace: PRIVYX
format: "<{namespace}_{type}_{id}>" # <PRIVYX_EMAIL_1>
# format: "[[{namespace}:{type}:{id}]]" # [[PRIVYX:EMAIL:1]]
# format: "<{namespace}:{type}:{id}>" # <PRIVYX:EMAIL:1>
formatmust contain{type}and{id}.{namespace}is optional.- Two placeholders need a delimiter between them.
- An invalid format fails at startup.
A token only comes back if the model writes it exactly, so pick a syntax your
model reproduces reliably. PRIVYX_TOKEN_FORMAT and PRIVYX_TOKEN_NAMESPACE
set these from the environment.
Two departures are tolerated. A model sometimes drops the outer delimiters, most
often in a tool argument or a title, and writes PRIVYX_EMAIL_1. That bare form
is restored too when the session issued the token and it stands between word
boundaries (PRIVYX_EMAIL_1 is not found inside PRIVYX_EMAIL_12 or
xPRIVYX_EMAIL_1). It needs a format that starts with {namespace} inside its
outer delimiters, as the three above do.
A model may also keep only the id, and write 247102A91C49C99E for
<PRIVYX_EMAIL_247102A91C49C99E>. The id alone is restored when it is at least
12 characters long, stands as a whole word, and belongs to exactly one token of
the session. The ids of an anchor, of hash at its default length,
and of encrypt are that long. A counter (1) is not: it is ordinary text, so
it is never looked for on its own.
Any other change to a token is left as written.
Anchors¶
By default a pseudonym token is a counter within its session:
<PRIVYX_EMAIL_1> is the first email address that session saw. In another
session the same address can get a different number, and <PRIVYX_EMAIL_1>
can stand for a different address.
Set an anchor secret and the id is derived from the value instead, so the same value gets the same token in every session and after a restart:
export PRIVYX_ANCHOR_SECRET=$(openssl rand -hex 32)
$ privyx detect --transform "mail alice@example.com"
...
mail <PRIVYX_EMAIL_247102A91C49C99E>
The id is an HMAC of the value under the secret. Anyone holding the secret can check a guessed value against a token, so keep it as private as an API key. With an empty secret there is no anchoring at all, rather than anchoring with a guessable key.
Anchoring applies to the pseudonym operator. privyx run creates a secret in
~/.config/privyx/anchor.key on first use; pass --no-anchor to skip that.