Audit log argument redaction
By default, Control Zero only persists the names of the arguments passed to each governed tool call. The values themselves are dropped at the SDK boundary before any data leaves the developer's machine. That default minimizes blast radius: a future leak of the audit store cannot expose customer commands, SQL, prompts, or filenames, because those values were never written.
Some teams need more. Compliance auditors want a richer paper trail. Incident responders want the original command text. This page describes the three storage modes you can choose from per organization, the trade-offs, and how to opt in.
Three modes
Redact (default)
- What's stored: argument key names only (e.g.
["sql", "user"]). - What's recoverable: nothing. The values were never sent to the server.
- Default for: SaaS organizations and self-managed deployments.
- Best for: highest-stakes environments where the audit pipeline must not retain customer-supplied text.
Encrypted with admin unmask
- What's stored: argument values, encrypted at rest with a per-org data key. The key is wrapped by an organization key encryption key managed by Control Zero's secrets vault. The vault key is never the same bytes as your organization's signing identity.
- What's recoverable: only org admins can unmask, and only via an endpoint that requires a freshly-verified multi-factor session.
- Every unmask writes a paired audit row containing the actor user id, the target audit row id, the multi-factor assertion id, and an optional reason. The paired row itself is never redacted, so a paper trail exists for every decryption.
- Best for: compliance-bound deployments that need argument-level visibility but cannot tolerate ambient plaintext.
Store full
- What's stored: argument values as plaintext JSON, alongside the argument key names.
- Visibility: org admins only. The audit list and detail endpoints redact values for non-admin viewers in the dashboard, but the data is on disk in plaintext, so the threat model is "the database is trusted."
- Default for: nothing. Opt-in only.
- Best for: single-tenant on-prem deployments where you already control the database and the audit pipeline. Not exposed on the hosted service.
Opting in
- Sign in to the dashboard with an org admin account.
- Navigate to Settings -> Audit.
- Choose a mode and click Save.
Mode changes are themselves admin-audit-logged. Switching from one mode
to another applies forward only; rows already on disk keep their
original storage shape. A switch from redact to
redact_with_admin_unmask cannot recover values that were dropped at
the SDK boundary; those bytes never made it to disk.
Unmasking under encrypted-with-admin-unmask mode
When you click Unmask on a row in the audit log:
- Control Zero verifies your session has a fresh multi-factor assertion. If the assertion is older than the configured freshness window, you are prompted for a step-up sign-in.
- The server fetches the wrapped data key for your organization, unwraps it with the organization's key encryption key, and decrypts the row's encrypted argument blob.
- A paired audit row is written before the plaintext leaves the server. If the paired write fails, the request fails closed and you never see the unmasked values.
- The decrypted values are returned and rendered inline. The UI surfaces "Unmasked by you at HH:MM. This action is logged."
Tampered ciphertext is detected on every read. A failed authentication
during decryption is treated as a security-relevant event and surfaces
to the unmask response with a typed ARGS_TAMPER_DETECTED error.
What admins see
The paired audit chain (visible in your audit log) lets you answer:
- Who unmasked which audit rows?
- When?
- Did they leave a reason?
Every unmask is itself one audit row. There is no quiet path to view the underlying values; even an org owner cannot disable the chain.
Common questions
Does the SDK still drop arg values under modes other than redact?
No. Under redact_with_admin_unmask and store_full, the SDK sends
argument values to the server, where the server applies the org's mode.
Under redact, the SDK still drops values at the boundary so they
never traverse the network in the first place.
Can I rotate the per-org data key? Yes. The wrapped key envelope carries a version number and the audit table records which version sealed each row. Rotation is a server-side operation; rows sealed under the old version remain readable until they age out of the audit retention window.
What happens on a tier downgrade?
redact_with_admin_unmask is available on Solo and Teams tiers on the
hosted service. If your subscription downgrades to Free, the org will
fall back to redact for new rows; existing encrypted rows remain
unmaskable until the audit retention window expires.
Where is the encryption key stored? The per-org key encryption key lives in Control Zero's secrets vault (the same vault that holds the organization's signing material) but is stored under a separate identity. Reusing one key for both signing and data encryption is a known compromise pattern; we keep them apart by design.