PASTKEYS · technical whitepaper PK-WP-001 · rev 1.0 status: live Home · Log in · Sign up
WHITEPAPER zero-access credential brokering

Zero-Access Credential Brokering for AI Agents

The agent requests an authorized operation, not a secret.

AI agents now take real actions on real infrastructure, and to do that they need credentials. The common practice is to hand the agent a long-lived provider secret and hope it never leaks. PastKeys removes the secret from the agent entirely: an agent authenticates as itself and requests an operation, and the broker decides whether it is allowed, uses the narrowest credential needed, and returns only the result. Provider tokens are stored sealed to a key whose private half lives only on the customer-operated broker, so the vendor stores ciphertext and holds no key. That the vendor cannot decrypt a customer's credentials is a property of the cryptography, not a clause in a contract.

Version 1.0  ·  2026-09-23  ·  pastkeys.com

01 the problem

A secret inside the agent is the vulnerability.

An agent that can act needs authority to act. Today that authority is usually a bearer secret placed inside the agent's reach. This creates several distinct failure modes at once:

  • Leakage surface. A provider key that passes through an agent can end up in a prompt, a model's context, a trace, a log line, an error message, or a cached tool result. Any one of those is an exfiltration path.
  • Blast radius. A leaked long-lived key typically carries broad, standing permission. The damage is bounded by the key's scope, not by what the agent was actually asked to do.
  • Prompt injection. An agent instructed by hostile input will do what it is told. If the agent holds the credential, the injection holds the credential.
  • Weak attribution. When several agents share a key, the provider's own logs cannot tell you which agent, which task, or which intent used it.

Secret managers and workload brokers each address part of this, but they share a common weakness: at some point a vendor-held or vendor-reachable key can decrypt the secret. PastKeys is built so that no such point exists.

02 design principles

Enforced in code, not recommended in configuration.

  • Default deny. Only an explicit rule permits an action. An unknown agent, an unknown resource, or any evaluation error resolves to deny.
  • Least privilege. The broker issues the narrowest resource, action, and lifetime a task needs, preferring short-lived scoped credentials wherever the provider supports them.
  • Never trust the agent. The broker authorizes the operation, not the prompt. What the agent was told is irrelevant to what it is allowed to do.
  • Never expose the credential. Provider secrets stay broker-side. They are never returned in a response, written to an audit event, or placed in an error string or stack trace.
  • Fail closed. Ambiguity and failure both resolve to deny.
  • Complete, tamper-evident audit. Every request produces one secret-free event in a hash-chained log.
03 architecture

Three components, three trust planes.

Components

  • Broker. Customer-operated. Holds the custody private key, evaluates policy, mints and uses provider credentials, writes the audit log. This is the only component that ever handles plaintext secrets, and it runs inside the customer's boundary.
  • Control plane. The web dashboard and account system. Manages accounts, workloads, policies, and human approvals, and stores sealed credential blobs. It never holds the custody private key.
  • Agent integration. A thin client, including a Model Context Protocol server, through which an agent presents its identity and requests an operation.

Trust planes

  • Session (human to dashboard): opaque database-backed sessions, login two-factor, CSRF protection.
  • Broker token (control plane to broker).
  • Agent identity (agent to broker): a short-lived signed token, verified by OIDC/JWKS in production or an HMAC verifier for local development.

The broker runs in one of two modes. In co-located mode it talks to the control-plane database directly; in API mode it reaches the control plane over HTTP with a broker token. In both modes the custody private key stays on the broker host and nowhere else.

The credential exists only inside steps 4 and 5, on the broker, for one operation. It is never part of what returns to the agent.

04 zero-access custody

The vendor holds ciphertext and no key.

This is the property that defines PastKeys.

The scheme

Custody uses an anonymous public-key sealed box, built only from the Go standard library (crypto/ecdh, crypto/hkdf, crypto/cipher). Anyone holding the broker's public key can seal a token to it; only the holder of the private key can open it.

Both public keys are bound as AEAD additional data, so a sealed blob cannot be re-pointed at a different recipient. A wrong key or any tampering returns a decryption error and never plaintext. This is verified by test.

Where the keys live

  • The broker generates the keypair and holds the private key locally, in a file it references at startup. It is never logged, printed, or transmitted.
  • The control plane and dashboard only ever have the public key. Tokens are sealed in the customer's browser or on the broker; the control plane stores and moves only ciphertext.

Because the datastore only ever contains ciphertext, the storage backend can be swapped without weakening the guarantee. A stolen datastore or a fully compromised vendor control plane yields sealed blobs and nothing else.

Key rotation

The broker holds an ordered set of custody keys. The current key seals new tokens and publishes its public key; previous keys are retained only to open older blobs. When a read opens a blob with a previous key, the broker lazily re-seals it forward to the current key. The fleet migrates to a new key as credentials are used, with no bulk re-encryption step and no downtime, and older keys can eventually be retired. The wire format is unchanged, so rotation is fully backward compatible.

Bring-your-own-key direction

The private key can be sourced from a customer KMS or HSM instead of a file, so the key material never leaves the customer's cryptographic boundary. This is the natural enterprise upgrade and does not change the wire format.

05 identity and authentication

Short-lived tokens, hardened against reuse and drift.

Agents present a short-lived signed identity token. Verification sits behind a common interface with two implementations: real OIDC/JWKS verification (RS256/ES256) for production, chained with an HMAC verifier for local development. The OIDC audience is validated against the configured value, which closes a confused-deputy path where an agent could present a token minted for a different service.

  • Clock skew tolerance. Expiry and not-before checks apply a bounded leeway so that legitimate requests near a boundary are not rejected on clock differences alone.
  • Replay protection for single-use tokens. Each token carries an issued-at time and a unique identifier. A short-lived, single-use token is tracked by a replay guard for the remainder of its lifetime; presenting it twice is rejected. Long-lived, deliberately reusable bearer tokens are never placed in the replay set, so the guard cannot grow unbounded and legitimate reuse is not broken. The guard is time-bounded and self-pruning.

In co-located mode the broker fails closed on identity: it refuses to start with the default development secret. A real secret from the secret manager, or an OIDC issuer, must be configured. The first-party broker binds to localhost only.

06 authorization

Default-deny, two-pass, fail-closed.

A request names a provider, a resource, an action, and parameters. The engine evaluates in two passes:

  • Deny wins. Any matching deny rule rejects the request immediately, with reason explicit_deny.
  • Allow. Only an explicit allow rule then permits it. No match means deny.

The decision records which rule matched, which is carried into the audit event. Beyond provider, resource, and action, a rule can additionally constrain:

  • Parameters. one_of and not_one_of, prefix, regex (anchored full-match, compiled and cached), and min/max numeric bounds.
  • Time windows. not_before and not_after bound when a rule is active.
  • Rate limits. A rule can cap how often its action runs in a window; over the cap the request is denied with reason rate_limited.

Parameter constraints matter because they narrow what an allowed action may touch, not just whether it is allowed. An agent permitted to read from S3 can be held to a specific bucket prefix; an agent permitted to run a query can be held to a set of statements.

07 human-in-the-loop approval

What the human saw is exactly what runs.

Some operations should not proceed on an agent's say-so alone. A policy can mark an action as requiring human approval. When it does:

  • The broker does not execute. It records a pending approval capturing the full operation, including a fingerprint of the exact parameters, and returns a request identifier to the agent.
  • A human reviews the pending operation in the dashboard and approves or denies it. The decision requires an authenticated session and CSRF protection, and is attributed to the operator who made it.
  • On approval, execution claims the approval atomically, so it cannot be executed twice or after it expires, and runs the operation using the stored, operator-approved parameters, not parameters re-supplied at execution time. This closes the time-of-check to time-of-use gap.
  • Approvals expire. If no store is configured, the create path fails closed with a refusal rather than silently executing.

An agent can also check, before acting, whether an operation would require approval, so it can set the right expectation with its human.

08 scoped, short-lived credentials

Mint the narrowest credential, cache it safely.

Where a provider supports it, the broker mints a fresh credential scoped to the operation and short in lifetime, rather than reusing a standing secret:

  • AWS: STS AssumeRole session credentials.
  • GitHub: a GitHub App installation token scoped to the repository and permission.
  • Postgres: a dynamic role with a VALID UNTIL expiry.

Two providers are handled as honestly documented long-lived pass-through: Cloudflare and generic HTTP. Their tokens are used only inside the broker and never returned to the agent; per-call scoped minting for them is future work, and this document does not claim otherwise.

Mint caching. Minting can be expensive, a call to STS or the GitHub App API per operation. The broker keeps an optional bounded, time-trimmed cache of minted short-lived credentials, keyed by a secret-free scope hash. A cached credential is reused only while a comfortable safety margin remains before its expiry, so a credential is never served close to expiry. The long-lived root is never cached. On any provider error the broker invalidates the relevant cache entry, so a revoked or rejected credential is re-minted on the next attempt rather than served again from cache.

09 audit

One secret-free event per request, hash-chained.

Every request produces exactly one event, and events contain no secret data. The event type has no field capable of holding a credential value; this is enforced by test, not left to discipline.

The log is append-only JSONL with a SHA-256 hash chain: each event commits to the previous one, so any insertion, edit, or deletion breaks the chain, and a verify command detects tampering. Events are enriched with request latency, a fingerprint of the request parameters (a hash, never the values), the rule that matched, and an error class, so an operator can reason about behavior and failures without any secret entering the log. A write-once or SIEM sink is the recommended production addition.

10 operational security

The surface around the core is hardened too.

Control plane. Argon2id password hashing (64 MiB, t=3, p=2, 10-character minimum); login two-factor by emailed one-time code with hashed codes, a short TTL, an attempt cap, and throttled resend; email verification for new accounts; opaque database-backed sessions (HttpOnly, Secure, SameSite=Lax) with double-submit CSRF on every state-changing request; per-IP and per-account rate limiting with lockout on login, signup, reset, verify, and two-factor; no user enumeration; and a strict header set (HSTS, a CSP with no inline scripts, X-Frame-Options: DENY, nosniff, a same-origin referrer policy).

HTTP layer. Panic-recovery middleware, a request-body size cap on mutating methods, constant-time login comparison, and a bounded per-provider execution timeout with a clear error taxonomy (mint_failed, provider_error, timeout).

Host and deployment. Services run as a dedicated non-root user under extensive systemd sandboxing (NoNewPrivileges, ProtectSystem=strict, a restricted system-call filter, an empty capability set, MemoryDenyWriteExecute, and more), bound to localhost. Secret files are owned by root and readable only before privileges drop; the custody key is group-readable only by the service user. The origin is reachable only over a private Cloudflare Tunnel, so the host exposes no public ingress ports, with a modern TLS floor at the edge. Transactional email is sent over an authenticated relay with SPF, DKIM, and a DMARC policy of quarantine. Secret values live in a secret manager and never in source control; the repository records only where a secret lives, never its value.

11 threat model

How each threat is bounded.

ThreatHow PastKeys bounds it
Prompt injectionThe broker authorizes the action, not the prompt. Default-deny policy bounds blast radius regardless of what the agent was told.
Compromised agent runtimeNo long-lived provider secret is present to steal; the agent holds only a short-lived identity token.
Stolen agent identityTokens are short-lived and revocable, single-use tokens are replay-protected, policy still limits the identity, and audit attributes every use.
Stolen datastore or compromised vendor control planeOnly sealed ciphertext is exposed. The private key is not present, so decryption is impossible.
Credential replayShort-lived scoped credentials expire quickly; single-use identity tokens cannot be re-presented.
Privilege escalationExplicit resource, action, and parameter constraints; no silent broadening; unknown agent denies.
Confused deputyOperations bind to the authenticated principal, not agent-supplied identity fields; OIDC audience is validated.
Audit tamperingSHA-256 hash chain detects any insertion, edit, or deletion.
Secret leakage via logs or responsesSecrets are never placed in events, responses, or errors; enforced by test.
If the broker itself is compromised, an attacker can reach provider credentials, because the broker is where they are used. This is the one case the architecture cannot make impossible, and PastKeys does not pretend otherwise. What it does is make such a breach bounded and detectable: credentials are isolated to the broker, egress is minimal, provider tokens are least-privilege, issuance is short-lived and scoped, keys rotate, and the audit trail is tamper-evident. A breach is time-bounded and visible, not permanent and silent.
12 what is not yet built

Trust is earned partly by being honest about the edges.

  • The default development secret backend is in-memory (wrapped by the envelope so it still stores only sealed blobs). A persistent hardened backend is the next step.
  • Cloudflare and generic HTTP providers pass a protected long-lived token through rather than minting per call.
  • Postgres disables an expired temporary role's login at its TTL; a reaper to drop expired role objects is future work.
  • Hardware-backed keys and TPM or workload attestation (SPIFFE/SPIRE), full break-glass workflows, and risk-based authorization are designed directions, not shipped features.
13 why the architecture is the point

An answer in math, not a promise.

A credential broker asks its customers for the most sensitive thing they have: the keys to their infrastructure. Most brokers answer the resulting trust question with policy, with a promise not to look. PastKeys answers it with math. The vendor holds ciphertext and no key, so "we cannot decrypt your credentials" is a checkable property of the system rather than a statement of intent. Every other control in this document, policy, identity, approval, audit, hardening, sits on top of that foundation and makes the bounded cases smaller.

The agent requests an authorized operation, not a secret. That single change is what makes agentic access to real infrastructure safe to run.