Zero-trust by design
Your data never leaves your network.
The Subveil CLI does the subsetting and masking inside your infrastructure. Subveil Cloud is a control plane for policies and receipts, and never sees a row.
Zero-trust execution
Runs entirely in your VPC or CI runner
subveil pull connects from your network to your databases. The only outbound traffic to Subveil Cloud is metadata and hashed receipts.
Your VPC · GitHub Actions runner · laptop
Production Postgres
read-only snapshot
subveil pull
subset + mask in-flight
Staging / PR DB
masked copy
Raw rows: stay here.
Subveil Cloud
- Schema metadata and PII hints
- Masking policies
- Audit receipts (hashes, counts)
- Accounts and billing
What Subveil Cloud stores
- Account, team and billing records
- Table and column names, types and PII hints
- Masking and subsetting policies
- Audit receipts: run IDs, timestamps, hashes, row counts, masked column names
What it never receives
- Row values from your databases
- Database connection strings or credentials
- Your SUBVEIL_SEED
- Anything the CLI reads from the source other than catalog metadata
Read-only source guarantee
Your source database is never mutated
Every pull reads the source inside a single REPEATABLE READ snapshot opened as read-only. All tables are read as of the same instant, so the slice is consistent even while production keeps taking writes.
- Source access is read-only: the database itself rejects writes.
- The CLI refuses to run when source and target are the same database.
- The CLI refuses a non-empty target unless you pass --truncate.
- The target is written in one transaction: it fully succeeds or leaves nothing.
- Row values never appear in logs or error messages.
BEGIN ISOLATION LEVEL REPEATABLE READ, READ ONLY;-- every table is read from this one consistent snapshotSELECT … FROM public.users WHERE …;SELECT … FROM public.orders WHERE …;COMMIT;Deterministic HMAC masking
Joins survive. PII doesn't.
Masking is keyed by SUBVEIL_SEED. The same input with the same seed always produces the same fake output, so a customer email masked in users and in billing stays identical, and foreign keys and unique constraints still hold.
Without the seed the mapping can't be recomputed. The seed lives in your environment or CI secret store and is never uploaded.
users.email [email protected] → [email protected]billing.contact [email protected] → [email protected]analytics.user [email protected] → [email protected]Audit receipts
Evidence for your SOC 2 and HIPAA reviews
After every pull the CLI submits a receipt. It records what ran (hashes of the policy, source and target hosts, row counts, masked column names) and never what the data was. Receipts are kept as an immutable log you can export for auditors.
Receipts help you evidence your controls. They do not by themselves make an environment SOC 2 or HIPAA compliant.
{ "run_id": "9b1e6f0a-3c52-4d7e-8a41-2f7c5d9e1b30", "started_at": "2026-10-21T10:00:00Z", "finished_at": "2026-10-21T10:01:15Z", "status": "success", "source_host_hash": "sha256:4be1…9c07", "target_host_hash": "sha256:a3f2…71d8", "policy_hash": "sha256:9f2c…b71e", "total_rows_copied": 2360000, "tables_summary": [ { "table": "public.users", "rows_copied": 50000, "masked_columns": ["email", "phone"] } ]}Questions from your security team?
Read how the pipeline works, or report a vulnerability to [email protected].