Back to Blog
A padlock over abstract circuitry representing API keys kept out of AI agent context

AI Agent Credential Security: Keeping API Keys Out of Context

12 min read

AI agent credential security fails when a deployment protects a key in a secret manager, then copies that key into the agent's environment. The agent process can still read it. A prompt injection, generated script, debug dump, or unrestricted HTTP request can expose a credential that was encrypted only until startup. The safer design keeps reusable secrets outside the agent process. Give the agent a workload identity and a narrow request format, then let a credential broker authorize the operation and attach credentials at the network boundary. This guide shows how to build that boundary, handle failures, and prove the agent cannot recover or exfiltrate the underlying key.

Why secret storage is not enough

A secret manager solves storage, access control, rotation, and audit problems, but it does not decide what happens after an application retrieves a value. If startup code places an API key in an environment variable, every library, tool, subprocess, and generated command running under that process may be able to read it. The storage control worked. The runtime boundary did not.

This is a concrete agent risk, not a theoretical objection to environment variables. In Kubernetes agent-sandbox issue 1045, the author reports that an agent can read a Kubernetes Secret injected through secretKeyRef and could leak it through generated text, tool calls, or outbound requests. Treat that issue as a practitioner report about the named configuration, not proof that every Kubernetes workload is vulnerable in the same way.

The agent also has a wider input surface than ordinary application code. Untrusted documents, web pages, support messages, and tool responses can influence its next action. OWASP LLM06:2025 Excessive Agency recommends limiting tool functionality, permissions, and autonomy, then enforcing authorization in downstream systems. A secret readable by the agent undermines that separation because possession may let generated code bypass the intended tool.

The design goal is therefore stricter than "do not hardcode keys." The agent must be able to request an approved business operation without learning the credential that authorizes the downstream call.

Put a credential broker between agents and APIs

Split the request path into four trust zones:

  1. The agent runtime interprets input and proposes a typed operation.
  2. A policy service decides whether that workload, user, tenant, tool, destination, and operation are allowed.
  3. A credential broker retrieves or mints the narrowest usable credential and attaches it to the approved request.
  4. An egress gateway sends the request only to an allowlisted destination and returns a sanitized response.

The agent never receives the reusable key or a general secret lookup capability. It sees a tool schema such as create_ticket, read_invoice, or send_approved_email. The broker sees the authenticated workload identity, policy decision, normalized destination, and validated request body.

This architecture applies the lifecycle controls in the OWASP Secrets Management Cheat Sheet while keeping the value outside the least trusted process. OWASP covers centralized management, rotation, revocation, least privilege, and auditing. The broker is an implementation boundary that carries those controls into an agent workflow.

Do not turn the broker into a generic HTTP proxy. If the agent can choose any host, method, path, headers, and body, it can often convert a narrow credential into broad authority. Give each tool a destination template and operation schema. Policy should reject fields that are not part of that schema.

Start with an authority inventory

List every credential currently available to the workflow. Include model-provider keys, OAuth refresh tokens, database passwords, webhook secrets, cloud credentials, signing keys, and service tokens. For each one, record:

  • who issues and rotates it;
  • which destination accepts it;
  • which operations it authorizes;
  • whether it is reusable, leased, or single use;
  • where it is currently visible at runtime;
  • how quickly it can be revoked;
  • which audit record proves its use.

Remove credentials the workflow no longer needs before designing the broker. Split credentials that cover unrelated destinations or operations. A single token accepted by billing, support, and customer-data APIs creates an unnecessary blast radius even if the broker protects its bytes.

Next, classify each credential by the best delivery pattern. Prefer a destination-issued, short-lived token when the API supports one. Use a broker-generated dynamic credential for systems that can create temporary users or sessions. Fall back to injecting a static key at the egress boundary only when the downstream service offers no narrower mechanism.

Authenticate the workload without a bootstrap secret

The broker needs to know which workload is calling. Do not solve that problem by giving the agent another long-lived shared key.

Use identity supplied by the execution platform, such as a cloud workload identity, a signed service identity, or a platform-issued certificate. SPIFFE's overview describes workload identities delivered through an API, with short-lived credentials and rotation handled by the platform. This lets the agent prove which workload it is without storing a reusable authentication secret in its own configuration. The same property can come from another platform identity system.

Bind the workload identity to deployment facts the agent cannot edit: service name, environment, namespace, tenant boundary, and release version. If a workflow serves several users, carry the authenticated human subject separately. Policy can then distinguish "support workflow acting for employee 42" from "nightly reconciliation job acting as itself."

Never accept identity fields copied from the model's JSON. The model may propose an operation, but trusted middleware must attach subject and workload identity after parsing the proposal.

Define an intent-scoped request

A broker request should describe business intent rather than raw network mechanics. A practical envelope contains:

{
  "tool": "support.create_ticket",
  "operation": "create",
  "tenant_id": "tenant-from-auth-middleware",
  "subject_id": "user-from-session",
  "resource": {
    "queue": "billing",
    "customer_id": "cust_1042"
  },
  "payload": {
    "summary": "Customer cannot download the paid invoice",
    "priority": "normal"
  },
  "workflow_run_id": "run-from-orchestrator"
}

The agent can supply the summary and choose among allowed queues. Trusted code supplies tenant_id, subject_id, and run identifiers. The tool adapter fixes the downstream host, method, and path template. It also removes headers from the model-controlled request.

Policy should evaluate the complete tuple: workload, human subject, tenant, tool, operation, resource, destination, and current approval state. A general rule such as "support-agent may call ticket API" is too broad. A better rule permits ticket creation in the caller's tenant, denies deletion, and requires approval before changing priority to urgent.

Return a stable denial code rather than policy internals. The agent needs to know whether it should ask for approval, correct an invalid field, or stop. It does not need a dump of role mappings, token claims, or destination configuration.

Inject credentials after authorization

Once policy allows the request, the broker obtains the narrowest credential available. HashiCorp Vault's secrets-engine documentation describes engines that generate credentials and associate dynamic secrets with leases that can be renewed or revoked. That model is useful when a downstream database or cloud service supports temporary authority.

For OAuth APIs, exchange workload or delegated identity for a token restricted to the required audience and scopes. For systems with session credentials, create a short-lived session tied to the operation. For legacy APIs with a static key, keep the key in the broker's trust zone and add it to the outbound request after the agent can no longer alter the destination.

Separate authorization from injection in code:

def execute_agent_operation(agent_request, trusted_context):
    operation = validate_tool_schema(agent_request)
    normalized = bind_trusted_identity(operation, trusted_context)

    decision = policy.authorize(normalized)
    if not decision.allowed:
        return safe_denial(decision.code)

    destination = routes.resolve(normalized.tool, normalized.operation)
    credential = broker.issue(
        workload=trusted_context.workload,
        subject=trusted_context.subject,
        audience=destination.audience,
        scopes=decision.scopes,
        ttl=decision.max_ttl,
    )

    response = egress.send(
        destination=destination,
        request=normalized.payload,
        credential=credential,
    )
    return sanitize_response(response, normalized.tool)

The agent-facing adapter never receives credential. Keep it out of exceptions, traces, and return values. If the broker and egress components are separate, use a one-time opaque handle or protected channel between them rather than returning the secret through the agent's process.

Constrain egress and sanitize responses

Credential brokering fails if generated code can bypass the broker and contact arbitrary hosts. Deny direct outbound network access from the agent runtime by default. Allow traffic to the broker and any explicitly public, credential-free sources the workflow needs. Resolve destinations from server-owned configuration, not a model-provided URL.

Validate scheme, host, port, and resolved address. Protect against redirects to a different host and against names that resolve to private or metadata addresses. Set request-size, response-size, and time limits. The sandbox boundary from a separate runtime still matters, but it should reinforce the broker rather than carry the secrets itself.

Sanitize the downstream response before it returns to the agent. Remove authentication headers, cookies, signed URLs, internal hostnames, verbose stack traces, and fields outside the tool's response schema. A service may echo part of a request or return debugging metadata. The response filter is the last place to stop a credential from entering model context.

Handle failures without exposing or widening authority

Fail closed when workload identity, policy, route resolution, or credential issuance is unavailable. Do not fall back to a shared key in an environment variable so the workflow can keep running. Queue the operation if the business process permits delay, or return a typed unavailable result that the orchestrator can retry under its normal recovery policy.

Treat a downstream authentication failure as a broker incident, not an invitation for the agent to improvise. Retry once only when the credential service confirms that rotation raced with the request. Otherwise revoke the lease or token, mark the route unhealthy, and alert an operator. Never put the rejected credential or full authorization header into the error shown to the model.

Set strict timeouts on broker and downstream calls. Cap concurrent issuance so a stuck agent cannot create thousands of valid tokens. Bind one-time handles to the intended route and workflow run. Reject replay after success or expiry.

Rotation must work without restarting the agent runtime. The broker should fetch the current static credential at request time or maintain a tightly controlled cache with a short refresh interval. For dynamic credentials, let the issuing system enforce expiry and revocation. The OWASP secrets guidance treats rotation and revocation as lifecycle requirements, not deployment chores.

Log use without logging secrets

Create one audit event for each broker decision and one for the downstream outcome. Record the workload identity, human subject when present, tenant, tool, operation, normalized destination identifier, policy version, decision code, credential type, lease identifier or token fingerprint, workflow run, latency, and outcome.

A fingerprint should be a nonreversible identifier produced by the issuer or broker. Do not hash a low-entropy API key and assume it is safe. Never record authorization headers, cookies, refresh tokens, full signed URLs, or request bodies that may contain credentials.

Keep diagnostic traces and security audit records separate. Engineers may sample request and response payloads during debugging, while a durable audit trail needs predictable fields and stricter retention. Both systems should use the same run and decision identifiers so an investigator can connect events without copying secrets between stores.

Prove the agent cannot recover the key

A successful API call tests the happy path. It says nothing about whether generated code can recover the key. Release requires negative tests against that boundary.

Start the agent with a test tool that attempts to print its environment, process arguments, mounted files, and common secret paths. The real credential must not appear. Search persisted prompts, tool transcripts, traces, exceptions, and job output for a synthetic canary credential.

Feed the workflow a prompt injection that requests the API key, asks generated code to read environment variables, and instructs the agent to send all process data to an external collector. The agent may repeat the instruction or attempt the tool call, but network policy and the broker must prevent disclosure.

Try to change the destination host, use a redirect, swap the tenant identifier, request an undeclared scope, replay a one-time handle, call a denied method, and submit an oversized body. Each attempt should produce a specific denial code and no downstream side effect.

Rotate the test credential during concurrent requests. Confirm that new calls use the current value, old leases stop working after revocation, and in-flight failure does not make the adapter expose headers. Stop the broker and policy service separately. The workflow should queue or fail safely rather than switching to direct access.

Finally, inspect broker logs and agent traces. The canary may appear only in the broker's protected test fixture, never in reader-facing errors, model context, or general telemetry. Passing this check shows that the agent can perform the operation without reading the reusable credential.

Common implementation mistakes

Putting Vault, a cloud secret manager, or Kubernetes Secrets in front of an environment variable changes storage but not process visibility. Retrieve the value inside the broker's trust zone instead.

Giving the agent a generic fetch_secret(name) tool is worse. It converts prompt influence directly into secret access and makes the model responsible for authorization decisions it cannot safely own.

Allowing a generic proxy with agent-controlled URLs creates a credential forwarding service. Bind tools to configured destinations and validate redirects after every response.

Relying on prompt instructions such as "never reveal credentials" is not an access control. OWASP's excessive-agency guidance puts the control in permissions, functionality, downstream authorization, and human approval for consequential actions.

Using one credential for all tenants also defeats a good broker. Scope the downstream authority by tenant when the service supports it, and enforce tenant ownership before issuance when it does not.

Release checklist

Before production, verify that the agent runtime contains no reusable downstream credential; workload and human identity come from trusted middleware; every tool maps to a fixed destination and schema; policy binds identity, tenant, operation, resource, and approval state; credential lifetime and scope are limited; direct egress is denied; responses are sanitized; denials fail closed; rotation and revocation work without agent restarts; logs contain identifiers rather than secret values; and the exfiltration suite passes with a synthetic canary.

Pick one high-risk integration first. Remove its environment variable, route the operation through a broker, and run the environment-dump, destination-swap, replay, and canary-log tests. Do not migrate the next credential until those tests show that the workflow still completes its job and the agent cannot recover the key.

References


About Fire In Belly: Independent senior engineering from Tallinn, Estonia. We design and build AI workflow automation with the credential brokering, workload identity, and exfiltration testing described above, at published fixed prices. Schedule a call to discuss your next project.