Here is a mental model that changed how I think about AI agent security.
.env files are for applications. AI agents are users.
You would not give a human contractor your root password. You give them the specific access they need, scoped to the task, revokable when the task is done. But when you put credentials in a .env file that your AI agent reads, you are treating it like an application that needs those values, not like a user that needs to be authorized.
The difference matters because AI agents can be manipulated. Applications cannot be prompt-injected. Users can.
An attacker who can influence your agent's inputs through a malicious webpage, a poisoned document, a rogue plugin can redirect its behavior. If the agent holds your credentials when that happens, the attacker has your credentials.
This is not theoretical. It happened to 30,000+ OpenClaw users last month.
What Zero-Trust Looks Like for Agents
Zero-trust applied to AI agents means one thing: the agent is never trusted with credential values, regardless of its behavior.
Not "we trust the agent unless it misbehaves." Not "we trust the agent because the model is aligned." The agent structurally cannot access credential values because credential values are never given to it.
This is the difference between:
Trust-based — agent holds the key
import os
stripe.api_key = os.getenv('STRIPE_KEY')
response = stripe.Balance.retrieve()
and
Zero-trust — agent expresses intent, proxy handles credentials
agentsecrets call \
--url https://api.stripe.com/v1/balance \
--bearer STRIPE_KEY
In the second model, the agent knows that STRIPE_KEY exists and that it is used for Stripe. It never knows that STRIPE_KEY is sk_test_51H.... The credential resolution happens inside AgentSecrets, inside the OS keychain, at the transport layer — outside the agent's observable context.
A Full Migration from os.getenv to AgentSecrets
Step 1: Store your credentials
agentsecrets init
agentsecrets project create my-agent
agentsecrets secrets set STRIPE_KEY=sk_test_51H...
agentsecrets secrets set OPENAI_KEY=sk-proj-...
agentsecrets secrets set DATABASE_URL=postgresql://...
Credentials are encrypted client-side with AES-256-GCM, stored in your OS keychain, and synced to an encrypted cloud backup. The server stores only encrypted blobs it cannot read.
Step 2: Replace direct credential access
Before:
stripe.api_key = os.getenv('STRIPE_KEY')
response = stripe.Balance.retrieve()
print(response)
After:
agentsecrets call --url https://api.stripe.com/v1/balance --bearer STRIPE_KEY
The agent invokes this command. It gets the API response. It never sees the key.
Step 3: For Claude Desktop and Cursor — use MCP
npx @the-17/agentsecrets mcp install
This auto-configures the MCP server. Claude gets an api_call tool. When you ask Claude to check your Stripe balance, it calls the tool, AgentSecrets handles the credential, Claude sees the response.
Step 4: For any agent via HTTP proxy
agentsecrets proxy start
curl http://localhost:8765/proxy \
-H "X-AS-Target-URL: https://api.stripe.com/v1/balance" \
-H "X-AS-Inject-Bearer: STRIPE_KEY"
Any agent that can make HTTP requests or run shell commands can use the proxy. No SDK required.
The Audit Trail You Get For Free
Every proxied call is logged locally. Key names only — the struct has no value field.
Time Method Target Secret Status Duration
01:15:00 GET https://api.stripe.com/v1/balance STRIPE_KEY 200 245ms
If a malicious skill tried to use your Stripe key to call an unexpected endpoint, this log would show it. You would know which credential, which endpoint, and when.
That is the zero-trust model applied to AI agents: the agent is never trusted with values, every action is logged, and the audit trail makes anomalies visible.
GitHub: https://github.com/The-17/agentsecrets
ClawHub: https://clawhub.ai/SteppaCodes/agentsecrets
Creator: https://theseventeen.co
Top comments (0)