Skip to main content
[AVAILABLE] as a mechanism, [PARTIAL] as a system-wide guarantee. packages/execution-control, packages/connector-sdk. See the scope note below before treating this as true of every connector.

What it is

Credential resolution happens exclusively inside the gateway boundary, after every gateway check has passed. The caller that proposed the action, the Runtime, and the Policy Engine never see the credential a connector uses to actually act.
// packages/execution-control/src/SessionCredentialVault.ts
interface SessionCredentialVault {
  issue(...): Promise<SessionCredential>;   // single-use, time-bounded lease
  consume(sessionCredentialId: string): Promise<ExecutionCredential>;  // only once
  revoke(sessionCredentialId: string): Promise<void>;
}

Why it exists

If the entity proposing an action, increasingly an AI agent, ever held a live, reusable credential, every guarantee upstream (deterministic policy, signed authorization, gateway re-verification) would still leave that credential extractable and reusable outside the authorized flow. Credential isolation closes that gap structurally: there is no code path where a proposer receives a credential, because credentials are never routed to it in the first place.

How it behaves

export interface CredentialProvider {
  readonly providerId: string;
  resolve(connectorId: string): Promise<CredentialHandle>;
}
A CredentialHandle is opaque, resolved material, { providerId, credentialId, value }. CredentialVaultAdapter adapts any CredentialProvider into execution-control’s CredentialVault interface, so InMemorySecureConnector resolves credentials through it exactly as it always has. Two providers ship: StaticCredentialProvider (an in-memory map, hermetic tests and local development only) and EnvironmentCredentialProvider (resolves from process.env via a connector-to-variable-name mapping). A session credential is issued, consumed exactly once, and can be revoked:
// packages/execution-control/src/SessionCredentialVault.ts:86-110
async consume(sessionCredentialId: string): Promise<ExecutionCredential> {
  const record = /* ... */;
  if (record.revoked) {
    throw new Error(`Session credential has been revoked: ${sessionCredentialId}.`);
  }
  // ...
}

What “never leaks” means, precisely

A CredentialHandle’s value necessarily carries the resolved secret, a connector (e.g. HttpConnector) needs it to set an Authorization header. What must never happen is the secret reaching anywhere durable or observable outside that one ephemeral use:
  • Never in ConnectorEvidence. buildConnectorEvidence only ever reads ConnectorRequest/ConnectorResponse fields, never ConnectorExecutionContext.credential. redactSensitiveKeys additionally strips any response-metadata key that looks credential-shaped, as defense in depth against a connector author’s mistake.
  • Never in a thrown error. Both providers’ failure messages name only identifiers (connectorId, environment variable name), never a resolved value. Tested in packages/connector-sdk/tests/unit/credential-provider.test.ts.
  • Never as a raw value reaching a Connector. Every CredentialHandle is branded at creation (brandCredentialHandle); SdkConnectorExecutor rejects any credential that isn’t a branded handle. Tested end-to-end in gateway-integration.test.ts (“rejects a raw (non-provider-resolved) credential”).
  • Never in the Execution Trust Record. Only ConnectorEvidence (never the handle itself) is placed on ExecutionResult.metadata.connector, see Execution trust records.

Minimal example

const provider = new EnvironmentCredentialProvider({
  "vendor-payment": "VENDOR_PAYMENT_TOKEN",
});
const vault = new CredentialVaultAdapter(provider);
// InMemorySecureConnector resolves through `vault`, never the raw provider.
Scope, precisely: this mechanism is real and tested, but in the default server it is only ever exercised for one connector. packages/api/src/bootstrap/createCredentialProvider.ts wires exactly one mapping, { "vendor-payment": "VENDOR_PAYMENT_TOKEN" }, into one EnvironmentCredentialProvider, registered against the one connector the server wires up (see The gateway). The isolation guarantee (caller never sees the credential, single-use, revocable) is architecturally true for any connector routed through this seam, and is proven generically by the tests cited above, but making it true for a new connector today means writing bootstrap code (a new CredentialProvider entry, a new registry registration), not configuration. There is no dynamic, general-purpose “any connector automatically gets isolated credentials” path yet. Treat the isolation guarantee as proven for the mechanism and for vendor-payment specifically, not as a system-wide property of arbitrary connectors you haven’t wired yet.

[FUTURE]: cloud secret managers

Only the CredentialProvider interface seam is defined. No integration exists yet for HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, or Google Secret Manager. Any of these would implement CredentialProvider exactly like EnvironmentCredentialProvider does, no cloud SDK dependency has been added to this package, and none is implemented in this milestone.

Next

Gateway attestation

The request-bound signature that authenticates the gateway to a connector.

Add a connector with the Connector SDK

What wiring a new connector into this seam actually requires.