Managed credential encryption
When you paste a Postgres URL, Cloud encrypts it before it touches the database. In production, credentials are encrypted with AES-256-GCM using a per-region AWS KMS key — one CMK per region, not one per tenant — via envelope encryption: KMS generates a data key, the DSN is sealed under it. The ciphertext is bound to your account and region with an encryption context of{customerId, region}, enforced on both encryption and decryption. A decrypt request for the wrong customer or the wrong region fails closed — the credential can’t be decrypted out of context, even with access to the ciphertext.
The plaintext DSN is never persisted. It’s encrypted on the way in and only ever decrypted in-region to spawn the engine for a request.
Tokens stored as HMAC digests
Machine tokens are never stored in plaintext. Each token is hashed with HMAC-SHA256 under a per-region secret and only the digest is kept. When an agent presents a token, Cloud hashes the presented value and compares digests in constant time. This is why a token’s full value can be shown only once, at mint time: there’s no stored plaintext to show you later — only the digest and a short prefix/suffix for recognition.Per-agent least-privilege scope
Each agent credential reaches only the databases you grant it, at the access level you set — read or read/write. An agent never sees a database it wasn’t granted, and a credential carrying no grant fails closed: an agent that connects over OAuth with no database access is rejected, not silently given the whole project. This is least privilege at the credential, on top of the per-database policy the engine enforces on every query.Roles
Sensitive dashboard actions are restricted to owners and admins; members connect agents and query. See roles.Row-level security for audit
The hosted audit log is shared infrastructure, isolated per customer with Postgres row-level security. Every audit query is scoped to the requesting account’s rows by the database itself — isolation is enforced at the row level, not only in application code, and the policy is forced so even a privileged database role can’t read across customers.Region locality of secrets
Your region choice is a hard boundary for your secrets:- Credentials are encrypted under that region’s KMS key.
- Tokens are hashed under that region’s HMAC secret.
- Audit rows live in that region’s database.
Browser hardening headers
The dashboard sends a set of security response headers on every route — landing, sign-in, and the authenticated app alike:Content-Security-Policy: frame-ancestors 'none'andX-Frame-Options: DENY— the origin can’t be embedded in a cross-site iframe, so the dashboard can’t be clickjacked.X-Content-Type-Options: nosniff— no MIME sniffing.Referrer-Policy: strict-origin-when-cross-origin— referrers don’t leak full URLs cross-origin.Permissions-Policy: camera=(), microphone=(), geolocation=()— the page asks for no device APIs.Strict-Transport-Securitywith a two-yearmax-age,includeSubDomains, andpreload— browsers stay on HTTPS.
Defense in depth
Cloud’s encryption and isolation sit on top of the same enforcement self-hosters get — they don’t replace your database’s own permissions, so give each project’s databases a least-privilege database role as well. See the threat model for what Midplane does and doesn’t claim, and what’s in and out of scope.Threat model
What Midplane claims and doesn’t, and what’s in and out of scope.
Adversarial corpus
The bypass attempts pinned as permanent regression tests.