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")
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.)
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...
import openai
client = openai.OpenAI(api_key=os.environ["OPENAI_API_KEY"])
# The agent has the raw key in memory
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
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
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)
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:
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.
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
curlthe 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
curlto 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_PROXYin 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
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)