What is held where.

A credential never sits in plaintext on two sides of any boundary at once. Each zone has a different operator, a different blast radius, and a different recovery story if it falls.

/ zone 01 Customer device your laptop · your OS
Agent private key on disk
Identity token (signed JWT) in memory
SaaS credentials never here
/ zone 02 · edge AgentValet proxy stateless, regional, audited
Verified agent identity per request
Policy decision per request
Plaintext token in memory only
Keys at rest never here
/ zone 03 · vault Encrypted storage HSM-backed key vault + DB
Per-tenant KEK in HSM
Wrapped DEK encrypted
Wrapped credential encrypted
Plaintext anything never
/ zone 04 Upstream SaaS Slack, Stripe, Gmail, etc.
Original credential owns
OAuth grant scope-limited
Sees AgentValet calls only no privilege
1Agent signs a request with its private key. Identity proves itself.
2Proxy verifies, evaluates policy, fetches the wrapped credential.
3Vault unwraps the DEK using the KEK. Decryption happens once.
4Proxy forwards to the SaaS. Plaintext is freed before response returns.

Three keys. Three jobs. Three holders.

Each key has exactly one purpose and lives with exactly one party. No key can do another key’s job on its own. Compromise one and you lose one layer.

Identity key

Agent signing keypair

Proves which agent is calling. RS256 keypair, generated on the customer device. We never see the private half.

held byCustomer (private), AgentValet (public)
algorithmRSA 2048, RS256
used atEvery call, 60s JWT TTL
if lostRotate. Old key dead, agent re-installs.
Key Encryption Key (KEK)

Per-tenant master key

Wraps every per-credential DEK belonging to one customer. Stored exclusively in an HSM-backed vault. The key material never leaves the HSM.

held byAgentValet, in an HSM-backed vault
algorithmAES-256 (HSM-managed)
used atPer credential, to unwrap a DEK
if lostAll wrapped credentials for that tenant become unrecoverable. Kill switch.
Data Encryption Key (DEK)

Per-credential symmetric key

Encrypts one credential. Born fresh per credential, wrapped immediately by the tenant KEK, then stored as ciphertext alongside the wrapped credential.

held byStored encrypted in our DB · never at rest plain
algorithmAES-256-GCM
used atOnce, in memory, to decrypt the credential
if lostThat one credential is dead. Customer re-connects the platform.

From OAuth callback to dead memory.

Plaintext exists for the seconds it takes to encrypt or use. Outside those moments, the credential is ciphertext. The proxy is stateless across calls.

step01
Customer authorises a platform at customer browser · standard OAuth

The OAuth callback returns a token to AgentValet’s edge over TLS. The token exists in memory only. We immediately generate a fresh per-credential DEK, encrypt the token, wrap the DEK using the tenant’s KEK in the HSM, then forget both plaintexts.

step02
Ciphertext persists in the database at AgentValet DB · RLS-isolated per tenant

Only the encrypted credential, the wrapped DEK, the IVs and tags, and a reference to the KEK version are stored. Postgres Row Level Security enforces that one tenant cannot see another’s rows even with a stolen connection string.

step03
Agent makes a request at customer device → proxy · signed JWT

The agent signs a 60-second JWT with its private key, sends it with the call. The proxy verifies the signature against the public key on file, evaluates policy (scope, approval gate, rate limit) before touching any credential.

step04
Decrypt, call, free at proxy memory · single function scope

The HSM unwraps the DEK. The DEK decrypts the credential. The credential is attached to the outbound upstream call, the call fires, the response returns. The plaintext is dropped before the function returns. Nothing is logged that would let an operator reconstruct the token.

step05
Append the audit row at append-only ledger · tenant-scoped

An immutable audit row captures who, what, when, scope, result, and the size of the call. It does not capture the credential or the response body. The audit log is the only thing that persists after the call.

No actor sees more than its job needs.

Across five common actors, here is exactly what each can read about a credential. Cells are intentional. Where AgentValet engineers have access, it is metadata only.

Actor
Plaintext credential
Wrapped credential
Identity / policy
Audit metadata
Owner (your admin)via dashboard
Never
Full
Full
Agentvia use_platform
Never
Never
Self
Self
Approval delegatevia magic link
Never
Never
One action
One action
AgentValet operatorsupport & ops
Never
Never
Upstream SaaSSlack, Stripe, etc.
Theirs
Not theirs
Never
Never

Five kill switches, ordered by reach.

Each layer can revoke independently. From the smallest scalpel to the global cut, here is what each pull actually shuts down. None of them require AgentValet to ship code.

/ 01

Scope

Untick a scope on one agent’s permission row. Next call returns scope_not_granted. Upstream untouched.

one agent · one scope
/ 02

Agent

Suspend or revoke the agent. Its JWTs stop validating. Any other agents owned by the same human keep working.

one agent · all scopes
/ 03

Connection

Disconnect a platform at the owner level. All agents lose access to that SaaS instantly. The upstream OAuth grant is also revoked.

one platform · all agents
/ 04

KEK

Rotate or delete the tenant KEK. Every wrapped credential for that tenant becomes unrecoverable. Tenant-wide kill switch.

one tenant · everything
/ what we don’t do

The boundaries we hold even when it would be convenient not to.

  • We don’t log credentials. Not in dev, not in prod, not in error traces. Logs that touch decrypt paths are sanitised at source.
  • We don’t hold cleartext at rest. Anywhere. Not in dev, not in backups, not in caches.
  • We don’t share keys across tenants. Each tenant has its own KEK. A breach in one tenant’s envelope cannot decrypt another’s.
  • We don’t let operators bypass policy. AgentValet engineers can read metadata, never plaintext. The action proxy enforces the same policy on internal calls as customer calls.
  • We don’t pretend revocation is async. Scope changes take effect on the next call. There is no token that survives a dashboard change.

Want the full security pack?

We send a detailed architecture document, our DPIA template, and a written breach-analysis Q&A to security reviewers under NDA. If your compliance team needs to dig into any layer above before you can buy, this is the next conversation.