| Spoofing a read client by IP |
IPv4/CIDR allowlist, fail-closed. Proxy IP trusted only when VAULT_TRUST_PROXY is set behind a trusted proxy. |
| Spoofing an admin |
High-entropy bearer tokens; only SHA-256 fingerprints stored; constant-time check; revocation. |
| Tampering with stored ciphertext |
AEAD tag fails open; AAD binds ciphertext to name:version so rows can’t be swapped between secrets/versions. |
| Tampering to escalate read access |
RLS FORCEd + REVOKE FROM PUBLIC; only the scoped service role can touch rows. |
| Repudiation |
Append-only vault.audit_log with actor/IP/action/outcome. |
| Information disclosure from DB/WAL/standby theft |
Only ciphertext + wrapped DEK at rest; decryption requires the KMS key (separate trust domain). |
| Information disclosure via error messages |
Internal errors return a generic 500; crypto/DB detail is logged server-side only. |
Information disclosure via timing on /verify |
Constant-time comparison of presented value vs decrypted versions. |
| DoS via large bodies |
1 MiB request body limit; secret value size cap. |
| Elevation via rotation worker races |
rotation_jobs claimed with FOR UPDATE SKIP LOCKED; stale claims reclaimed; rotation is a primary-only write. |
| Nonce reuse weakening AEAD |
192-bit random XChaCha20 nonces, fresh per version; uniqueness covered by tests. |
| Key material in memory after use |
Zeroizing DEKs/master keys. The DEK cache holds unwrapped keys for up to VAULT_DEK_CACHE_TTL_SECS (never plaintext); lower or disable the TTL to shrink the window. |