PBPBV Design Notes
The PBPBV design name, the parts of it that ship, and the per-tenant BYOK and cryptographic-erasure parts that were design intent only. The working reference is the PII vault guide.
Overview
PBPBV is the internal design name for the Purpose-Bound PII Vault. This page is a design note kept for the name and the patent reference. The working reference for what ships is Purpose-Bound PII Vault, and the usage guide is PII Vault Access Patterns.
What the name covers in production today: one shared module (_shared/pii-vault.ts), one platform encryption key, one append-only audit table (pii_decryption_log), and a purpose-policy table the dashboard manages but no function reads. The design principle holds up, in that reading plaintext personal data is the exception and every exception is recorded with a declared purpose code.
Two parts of the original design are not built, and were previously described here as if they were: per-tenant bring-your-own-key encryption of PII, and cryptographic erasure by destroying a tenant's key. The last section on this page says what exists instead.
A patent application covers purpose-bound decryption with auditable purpose codes (Serial No. 64/014,323).
Ciphertext and keyed digest
Each covered field is stored twice, in two forms that are derived independently from the plaintext:
| Form | Produced by | Used for |
|---|---|---|
| AES-256-GCM ciphertext | encrypt() under the platform master key | Reading the value back for a declared purpose |
| Keyed HMAC-SHA-256 digest | hashIdentifier() under the server-held pepper | Equality lookups, correlation and audit references |
The digest is not derived from the ciphertext, and the ciphertext is not derived from the digest. Routine work touches only the digest: signal correlation, cross-reference binding and subject lookup all operate on 64 hex characters that cannot be reversed without the pepper. Reading the value itself requires the master key and goes through decryptPii, which records the access.
The digest is a keyed HMAC, never a plain SHA-256. Email addresses and phone numbers are drawn from small enough keyspaces that an unkeyed digest can be reversed by enumeration, which is the whole reason for the pepper.
Unimplemented parts of the design
Per-tenant PII keys. Every vault ciphertext is encrypted with the single platform master key, SHIELD_ENCRYPTION_KEY. There is no per-tenant PII key and no per-tenant key hierarchy for PII. _shared/pii-vault.ts imports encrypt and decrypt from _shared/encryption.ts, and those read that one key.
BYOK means signing keys. The product does have a bring-your-own-key path, in _shared/tenant-keys.ts, and it is unrelated to PII ciphertext. It imports an EC P-256 or P-384 private key (a JWK or a PKCS#8 blob) and uses it to sign credentials and attestations under ES256 or ES384. Imported keys carry a byok- key id prefix and platform-generated ones gen-. See Tenant Key Management and Rotation.
Cryptographic erasure by key destruction. Not implemented, and not achievable with the current key layout: the master key also protects BLAST session material, tenant private keys and every other tenant's PII, so destroying it would be a platform-wide event rather than an erasure for one data subject. Erasure in production is the DSAR tombstoning path: identifier columns nulled, encrypted columns overwritten with the literal SHREDDED, webhook delivery bodies nulled, and pii_decryption_log.user_hash unlinked while the audit row is kept. Every statement is scoped by tenant and hash and reads back its affected row count. See DSAR Workflows.
Plaintext lifetime. The decrypting function is decryptPii, not decryptForPurpose, which is a symbol that exists nowhere in the codebase. The value it returns is a local value inside the calling invocation and is never persisted, logged or cached by the vault. Nothing zeroes the string afterwards, so the honest statement is that the plaintext is not stored anywhere, and its lifetime in memory is whatever the runtime gives it.
Related from the blog
- The Pre-Filter Pattern: Paying for Heavy Fraud Signals Only on the Suspicious Tailsecurity · 9 min read
- Just-in-Time Capability Tokens for Agents: Why Persistent OAuth Scopes Are the New Standing Privilegesecurity · 14 min read
- The 200-Millisecond Blind Spot: What Happens Between SIM Swap and Detectionsecurity · 13 min read