Vault

Where the token-to-value mapping lives, how it is keyed, and who can read it.

The contract

Each vault entry relates a typed token to the value it replaced, together with its class, its tenant and the context it belongs to. That mapping is the one piece of information that can turn PHONE_qzvtrn back into a phone number, which makes it the most sensitive asset in the system. The design question is not whether such a mapping exists, reversibility requires it, but where it lives and who can use it. The answer is fixed: it lives in your PostgreSQL, under your key, and no external party, including the AI provider and including Salus, has an access path to it.

What is stored

Two tables: sessions, one per tenant and context, and tokens, one per entity in a session. A token row holds:

  • a keyed hash of the normalised value, used to find the token again on the next request
  • the token itself
  • the canonical value encrypted with AES-256-GCM under the vault key
  • a flag saying whether the value may be restored

The token’s six letters are derived from a keyed hash of the tenant, the context, the class and the normalised value, with collisions resolved deterministically under a lock. Model-originated values are stored with the restore flag off.

Keys

The vault key is a 64-hex-character secret you generate at install and keep in a Kubernetes secret or an environment variable. It is used both for the token derivation and for the encryption of stored values. Tenants and contexts are inputs to the derivation, not separate keys. Losing the key makes stored values unrecoverable; rotating it does not re-encrypt existing rows, so plan rotation as a migration.

A separate key encrypts matched text in the audit store, and a third, optional, drives format-preserving mode.

Retention

Sessions and tokens persist until you delete them. There is no automatic expiry on the vault; retention is a database operation under your own policy, and removing a session cascades to its tokens. Audit records have their own retention setting.

When the vault is unavailable

A protect call made while the vault database is unreachable still succeeds, with ephemeral tokens drawn from a random per-request key and a note in stats.warnings. Those tokens cannot be restored. Applications that depend on restore should treat the warning as a failure. The LiteLLM guardrail refuses to run without the vault.

All example values in this documentation are synthetic.