Vibecoding Is Leaking Your Secrets Into Chat Logs
Vibecoding Is Leaking Your Secrets Into Chat Logs
You're deep in a vibecoding session. Cursor, Claude Code, Codex—doesn't matter which. The agent can't figure out why the Stripe webhook is failing, so it does what any of us would do: it reads your .env file to check the keys. Then it prints them into the conversation to "verify" them. Then it pastes the connection string into a debug script it writes for you. Then it tells you it's fixed and moves on.
Nobody did anything malicious. Nobody even did anything unusual. And your production database URL now exists in plaintext in at least three places it didn't five minutes ago.
This is the part of the AI coding wave nobody's threat-modeling. We spent years training developers not to paste secrets into Slack. Then we handed them an agent that reads every file in the repo, holds it all in an unaudited context window, and often writes the whole session to disk when it's done.
The State of Vibecoding
"Vibecoding" caught on because it's an accurate description of how a lot of AI-assisted development actually happens: you describe the outcome, the agent writes and runs the code, and you review the diff instead of typing every line yourself. That workflow is genuinely good. Agents with real filesystem and shell access—not just autocomplete—are why tools like Claude Code, Cursor, and Codex have taken over so much day-to-day coding.
But "real filesystem and shell access" is the whole problem. An agent debugging a failed API call has every reason to cat .env, grep for a connection string, or write a one-off script that hardcodes a token "just to test it." A human developer does this too, but a human developer doesn't automatically forward what they just read to a third-party API and then persist a plaintext transcript of the exchange to disk—which is exactly what most agentic coding tools do by default, as part of normal operation, not a bug.
None of this requires a compromised dependency or a prompt injection attack. It's just Tuesday.
Why This Matters
Here's what's different about secrets leaking into an AI coding session versus the usual suspects:
Chat transcripts aren't scanned. Your secret-scanning tool watches git history, maybe Slack, maybe your CI logs. It is not watching ~/.claude/projects/*/transcript.jsonl or your Cursor session cache. If an agent read your AWS_SECRET_ACCESS_KEY to debug an S3 upload, that key is now sitting in an unencrypted local file that no scanner is looking at and no rotation policy accounts for.
Context windows don't expire on your schedule. A .env file gets rotated when you rotate it. A value that made it into an LLM provider's request logs is subject to their retention policy, not yours—and most teams have no idea what that policy actually is for the tool they installed last week.
Agents don't know which secrets are sensitive. To a human, STRIPE_SECRET_KEY and LOG_LEVEL look obviously different in weight. To an agent pattern-matching its way through a debugging task, they're both just environment variables that might be relevant to the error. It will read and repeat back whichever one helps it reason about the problem, with no sense that one of them should never leave the machine.
Multi-agent workflows multiply the exposure. The more agentic these tools get—subagents, background tasks, forked sessions—the more copies of your context get made. Every subagent that inherits a parent's context inherits whatever secrets were sitting in it, whether or not that specific subagent's task needed them.
None of this shows up as an incident. It shows up eighteen months later as "we're not sure how this key ended up in a support ticket" or "why is there a database URL in this markdown file the AI generated."
The Better Way
The fix isn't "don't use AI coding tools"—that ship has sailed, and the productivity gains are real. The fix is making sure the agent never needs to see the secret to use it.
Principle 1: Secrets belong in the process, not the prompt
If a value can be injected at the process level, it never needs to appear in a file the agent can read or a message the agent can generate. keyenv run -- npm start sets environment variables for the child process without ever writing a .env file to disk. There's nothing for the agent to cat, because there's nothing sitting in the working directory to find.
Principle 2: Scope the agent's blast radius, not just its instructions
Telling an agent "don't share secrets" in your CLAUDE.md or .cursor/rules is worth doing, but it's a suggestion, not a control. The actual control is permissions: an agent working in a feature branch should be running with development credentials, full stop. It should be structurally incapable of reading a production key, not politely asked not to.
Principle 3: Treat every AI session as an unaudited secrets store
Assume that anything an agent read during a session is now sitting in plaintext somewhere outside your normal security tooling—because it usually is. That means: rotate anything sensitive that an agent had cause to inspect, especially after a debugging session that involved live credentials. It's the same instinct as rotating a key after it touched a Slack DM, just applied to a newer channel.
Putting It Into Practice
The concrete version of this looks like:
# Instead of letting the agent read a .env file...
keyenv run -- npm run dev
The agent can still debug the failing request, inspect the app's behavior, and see that DATABASE_URL is set—it just never needs to read the value itself, because the value was injected directly into the process rather than written to a file in the repo.
For AI tools that support Agent Skills, you can go further and let the agent manage secrets through KeyEnv's CLI instead of around it:
npx skills add keyenv/keyenv-skills
That gives Claude Code, Cursor, Codex, and others a documented way to pull secrets, run commands with secrets injected, and scan for hardcoded values—using your existing CLI session and role-based permissions, not by reading raw files. The agent gets exactly the access your KeyEnv role grants, every action lands in the same audit trail as your other CLI usage, and no credential is ever shared with the AI provider itself.
A line in your project's CLAUDE.md or AGENTS.md reinforces the habit for the agent even without the skill installed:
## Secrets Management
This project uses KeyEnv. Never read .env directly—use
`keyenv run -- <command>` to inject secrets, and `keyenv pull`
to sync. Never commit or print secret values.
It won't stop every agent from ever touching a secret—sometimes debugging genuinely requires seeing a value. But it removes the default path, which is where almost all of this leakage actually happens: not attacks, just an agent doing exactly what you asked it to, with no boundary telling it where the secret should stop.
Final Thoughts
Vibecoding works because you've delegated judgment to the agent about how to get something done. That's fine for refactors and bug fixes. It's not fine for deciding which strings in your codebase are safe to read, repeat, and write to disk. Draw that line with infrastructure—runtime injection, scoped tokens, audit trails—instead of hoping every agent, every session, every provider policy happens to respect a comment in your CLAUDE.md.
TL;DR: AI coding agents read files and persist transcripts as a normal part of doing their job—which means any secret in a .env file an agent touches is now sitting in an unaudited plaintext log somewhere. Inject secrets at runtime with keyenv run, scope agent access by environment, and treat anything a session read as due for rotation.