DEV Community

Cover image for How OneCLI Secures AI Agent API Keys Without Code Changes
Jonathan Fishner
Jonathan Fishner Subscriber

Posted on

How OneCLI Secures AI Agent API Keys Without Code Changes

How OneCLI Secures AI Agent API Keys Without Code Changes

If you're running AI agents in production, you've probably done something like this:

import os
agent = Agent(
    openai_key=os.environ["OPENAI_API_KEY"],
    stripe_key=os.environ["STRIPE_API_KEY"],
    github_token=os.environ["GITHUB_TOKEN"],
)
agent.run("Process today's invoices and commit the report")
Enter fullscreen mode Exit fullscreen mode

The agent now has direct access to three API keys. It can read them, log them, or - if a prompt injection attack succeeds - exfiltrate them to an attacker-controlled endpoint. The keys live in the agent's memory for the entire session. One bad tool call and they're gone.

This is the default state of AI agent credential management today, and it's a problem that gets worse as agents become more autonomous and connect to more services.

The core problem

Traditional applications follow a predictable execution path. You audit the code, you know which endpoints get called, and you can reason about where secrets flow. Agents are different. They make decisions at runtime. They chain tool calls based on LLM output. They can be manipulated by adversarial inputs embedded in the data they process.

Giving an agent raw API keys is like giving a contractor the master key to your building and hoping they only open the doors they're supposed to.

What you actually want is a system where:

  • The agent can use credentials without seeing them
  • Credential access is scoped to specific services and endpoints
  • You have a single audit log of every credentialed request
  • Revoking access doesn't require redeploying the agent

How OneCLI solves this

OneCLI is an open-source credential vault and gateway that sits between your agents and the APIs they call. It works as a transparent HTTPS proxy - the agent makes normal HTTP requests, and OneCLI injects the real credentials at the network layer.

No SDK. No code changes. No secrets in environment variables.

Here's the architecture at a high level:

Agent (with placeholder key)
    |
    | HTTP request via HTTPS_PROXY
    v
OneCLI Gateway (Rust, Tokio/Hyper/Rustls)
    |
    | 1. Authenticate agent (Proxy-Authorization header)
    | 2. Match request to credential rule (host + path pattern)
    | 3. Decrypt credential from vault (AES-256-GCM)
    | 4. Inject real API key into request headers
    | 5. Forward request to target service
    v
External API (OpenAI, Stripe, GitHub, etc.)
Enter fullscreen mode Exit fullscreen mode

The agent never touches the real key. It doesn't even know the key exists. From the agent's perspective, it's just making a normal API call through a proxy.

Before and after

Before OneCLI - secrets live in the agent's environment:

# .env file that the agent can read
OPENAI_API_KEY=sk-proj-abc123...
STRIPE_API_KEY=sk_live_xyz789...
GITHUB_TOKEN=ghp_realtoken...
Enter fullscreen mode Exit fullscreen mode
import openai
client = openai.OpenAI(api_key=os.environ["OPENAI_API_KEY"])
# The agent has the raw key in memory
Enter fullscreen mode Exit fullscreen mode

After OneCLI - secrets live in the vault, agent uses placeholders:

# Agent's environment - no real secrets
HTTPS_PROXY=http://localhost:10255
OPENAI_API_KEY=placeholder
Enter fullscreen mode Exit fullscreen mode
import openai
client = openai.OpenAI(api_key="placeholder")
# The agent never sees the real key
# OneCLI intercepts the request and injects sk-proj-abc123... at the proxy layer
Enter fullscreen mode Exit fullscreen mode

The Python code doesn't change. The OpenAI SDK sends the request through the proxy (standard HTTPS_PROXY behavior), OneCLI matches the request to api.openai.com, decrypts the stored OpenAI key, swaps the Authorization header, and forwards the request. The response comes back to the agent as normal.

How credential matching works

When you add a credential to OneCLI, you define a matching rule:

Host pattern:  api.openai.com
Path pattern:  /v1/*
Header:        Authorization
Credential:    sk-proj-abc123... (encrypted, AES-256-GCM)
Enter fullscreen mode Exit fullscreen mode

When OneCLI sees a request to api.openai.com/v1/chat/completions, it matches the host and path, decrypts the credential, and replaces the Authorization header value. You can define rules for any service - Stripe, GitHub, AWS, your own internal APIs.

This matching is deterministic. The agent can't trick OneCLI into injecting credentials for a service it shouldn't access, because the rules are defined by you, not by the agent.

Agent authentication

Each agent gets its own identity, authenticated via the Proxy-Authorization header. This serves two purposes:

  1. Access control: Different agents can have access to different credentials. Your invoice-processing agent gets Stripe keys; your code-review agent gets GitHub tokens. Neither can access the other's credentials.

  2. Audit trail: Every credentialed request is logged with the agent identity, timestamp, target service, and path. You can see which agent accessed which service and when.

The TLS interception model

A fair question - and one that came up frequently during our Hacker News launch - is how OneCLI handles HTTPS traffic. After all, a proxy can't read or modify encrypted request headers without terminating the TLS connection.

OneCLI uses a standard MITM proxy approach: it generates a local CA certificate that agents trust, terminates the TLS connection from the agent, reads and modifies headers, then establishes a new TLS connection to the upstream service using Rustls.

This is the same model used by tools like mitmproxy, Charles Proxy, and corporate HTTPS inspection appliances. The trust boundary is explicit - you configure the agent to trust OneCLI's CA, and OneCLI runs on infrastructure you control.

For self-hosted deployments, the CA cert never leaves your machine. For cloud deployments, the TLS termination happens within OneCLI's infrastructure, and credentials are encrypted at rest with AES-256-GCM.

What this means in practice

Consider a real scenario: you're running an autonomous coding agent (like OpenHands or SWE-Agent) that needs access to GitHub and an LLM provider. Without OneCLI:

  • The agent has your GitHub token in its environment
  • A prompt injection in a malicious repository could instruct the agent to curl the token to an external server
  • Your GitHub token is compromised

With OneCLI:

  • The agent has a placeholder token
  • Even if a prompt injection succeeds, the exfiltrated value is useless
  • OneCLI only injects the real token for requests matching api.github.com
  • The curl to the attacker's server goes through the proxy with the placeholder - no credential injected

This doesn't make prompt injection impossible, but it removes credential theft from the attacker's toolbox.

Framework compatibility

Because OneCLI works at the network layer via standard HTTPS_PROXY, it's compatible with any agent framework:

  • LangChain / LangGraph: Set HTTPS_PROXY in the environment
  • n8n: Configure proxy in HTTP request nodes
  • Dify: Set proxy in environment variables
  • OpenHands: Pass proxy config at container startup
  • Custom agents: Any HTTP client that respects proxy settings

There's no OneCLI SDK to install, no wrapper functions to call, no middleware to configure. If the agent makes HTTP requests, OneCLI can secure them.

Getting started

OneCLI is open source under Apache 2.0. You can self-host it with Docker Compose:

docker compose -f docker/docker-compose.yml up
Enter fullscreen mode Exit fullscreen mode

Add a credential through the web dashboard at localhost:10254, set HTTPS_PROXY=http://localhost:10255 in your agent's environment, and you're done.

For managed hosting, check out app.onecli.sh. For docs and detailed setup guides, visit onecli.sh/docs.

The repository is at github.com/onecli - contributions and feedback welcome.


OneCLI is an open-source credential vault and gateway for AI agents. Give your agents access, not your secrets.

Top comments (0)