# Your AI Coding Agent Can Read .env — Here’s How to Stop Secrets Before They Reach the Cloud

> Source: <https://dev.to/3mre0s/your-ai-coding-agent-can-read-env-heres-how-to-stop-secrets-before-they-reach-the-cloud-4dg0>
> Published: 2026-08-18 14:50:30+00:00

AI coding agents do much more than autocomplete.

Tools such as Claude Code, Codex, Cursor, Aider, and Cline can read files, inspect directory trees, execute terminal commands, and feed the results back into a model. That context is what makes them useful—but it also creates a new path for accidental data exposure.

Imagine asking an agent to debug a failing deployment. It runs:

cat .env

The output contains values like these:

DATABASE_URL=postgres://admin:EXAMPLE_PASSWORD@internal-db:5432/app

GITHUB_TOKEN=ghp_EXAMPLE_TOKEN_NOT_REAL

INTERNAL_API_KEY=sk-example-not-a-real-key

The agent may include that command output in its next model request. At that point, the values are no longer only on your machine—they have become part of the outbound prompt.

.gitignore does not prevent this. Secret scanning at commit time does not prevent it either. The secret does not have to enter Git history to leave the workstation.

I wanted a control at the actual boundary: immediately before coding-agent traffic leaves the machine.

So I built Anonmyz, an open-source, local DLP proxy for AI coding agents.

The basic idea

Anonmyz runs on the developer’s machine between the AI client and the model provider.

For each supported request, it:

Intercepts the outbound request locally.

Scans its JSON body for supported secret and sensitive-data patterns.

Replaces detected values with cryptographically random placeholders.

Stores the placeholder-to-value mapping in a request-scoped, in-memory vault.

Sends only the sanitized request to the configured model provider.

Restores placeholders locally when the standard or streamed response returns.

Clears the request-scoped vault after the exchange finishes.

The model can still reason about the structure of the prompt, but it does not need to see the original credential.

What the provider sees

Consider an outbound request containing this text:

{

"input": "Debug this config: GITHUB_TOKEN=ghp_EXAMPLE_TOKEN_NOT_REAL"

}

After local masking, the provider receives something conceptually similar to:

{

"input": "Debug this config: GITHUB_TOKEN=[[GITHUB_TOKEN_7F3A9C2D]]"

}

The original value remains in the local request vault. If the model includes the placeholder in its response, Anonmyz replaces it locally before returning the response to the coding agent.

This is different from permanently replacing every finding with [REDACTED]. A unique placeholder preserves identity and context: the model can distinguish two different values without learning either value, and the local workflow can remain coherent on the return path.

Streaming makes this harder than it looks

Most coding agents stream model output using Server-Sent Events. A placeholder—or even a raw secret in an unsafe upstream response—can be split across arbitrary network chunks.

A naive implementation that scans each chunk independently can miss this:

chunk 1: sk-example-part-

chunk 2: two-not-a-real-key

Neither chunk necessarily matches a complete credential pattern by itself.

Anonmyz therefore keeps a bounded look-behind window while processing the stream. It delays emitting bytes that might be the beginning of a supported secret or placeholder, scans the combined boundary, and fails closed when the response cannot be handled safely.

This chunk-boundary behavior is covered with split-position tests rather than assuming that one network read equals one logical token or SSE event.

Why a local proxy?

Sending a prompt to a cloud DLP service before sending it to a cloud model creates another party that receives the sensitive prompt.

Anonmyz keeps the detection and reversible mapping on the workstation. The cloud provider receives the sanitized request; the mapping needed to reverse it remains local and in memory for that exchange.

The current implementation provides:

A loopback reverse-proxy mode for configurable AI clients

An optional transparent MITM mode restricted to allowlisted AI domains

Standard-response and SSE streaming support

Request-scoped in-memory vaults

Provider adapters and allowlisted header forwarding

Local metadata-only audit and metrics endpoints

A Codex Safe Session launcher

VS Code integration and a beta JetBrains integration

The core is written with the Go standard library and builds as a single binary. There is no Python or Node.js runtime required for the proxy, and Docker is optional rather than mandatory.

What it looks for

Anonmyz is designed to detect supported patterns such as:

API keys and provider tokens

GitHub tokens

SSH private-key blocks

Inline passwords and credentials

Sensitive local file paths

Other configured organization-specific patterns

Pattern matching is only one layer. Where useful, semantic validators reduce obvious false positives—for example, by checking whether a candidate has the expected structure instead of treating every random-looking string as a credential.

No detector recognizes every possible secret format. Unknown proprietary formats need custom patterns, and low-entropy values such as ordinary dictionary passwords are inherently difficult to identify without context.

The threat model matters

Anonmyz is intended to reduce accidental disclosure of supported secrets through AI traffic that is actually routed through the proxy.

It is not a defense against:

A malicious or already-compromised local process

A client that bypasses the configured proxy

Exfiltration through an unrelated network channel

Secret formats the detector does not recognize

Credentials that were already exposed before Anonmyz was enabled

It is also not a replacement for least-privilege credentials, secret rotation, endpoint isolation, or a full agent sandbox.

The proxy is one enforceable boundary in a layered security model—not magic dust for every agent-security problem.

Security work before promotion

Security tools deserve more scrutiny than ordinary developer utilities. A bug in the guardrail can create a false sense of safety.

During a static security review, several boundary problems were identified and fixed before the current release path:

IDE integrations no longer automatically execute a binary found inside an untrusted workspace.

Codex Safe Session routing and transport settings cannot be overridden by forwarded arguments.

Remote plaintext HTTP upstreams are rejected.

Stream processing retains credential look-behind across chunk boundaries.

Standard upstream responses have explicit size limits.

Newly generated CA keys use salted PBKDF2-HMAC-SHA-256 with 210,000 iterations.

The project also keeps a public threat model and treats bypass reports as security issues rather than ordinary feature requests.

That does not mean the project is “proven secure.” It means its claims are deliberately scoped and its boundaries are meant to be testable.

Try to break it

The most useful feedback for a project like this is not “nice work.” It is a reproducible bypass.

If you use an AI coding agent, you can help by:

Running Anonmyz with fake test credentials.

Inspecting what is actually sent to the upstream provider.

Trying unusual JSON nesting, tool-result payloads, and streaming boundaries.

Reporting false positives or unsupported secret formats.

Testing it with a client or provider adapter that is not covered yet.

The repository, setup instructions, threat model, and security policy are available here:

If the project solves a problem you have, a GitHub star helps other developers discover it. If it fails in your environment, an issue with a minimal reproduction is even more valuable.

AI coding tools should not have to be banned simply because they can see local context. We should be able to place a measurable, local security boundary between that context and the cloud.
