How to use AI coding agents (Claude Code, Cline, Cursor) without leaking secrets to cloud APIs.
When an AI agent reads your files, the contents are sent to the provider's API. If those files contain API keys, connection strings, or credentials, the secrets leave your machine.
Your machine Cloud API
┌──────────────┐ file contents ┌──────────────┐
│ source code │ ──────────────────► │ AI provider │
│ with secrets│ (secrets leak) │ │
└──────────────┘ └──────────────┘
This is not hypothetical. Config files, .env files, and hardcoded credentials are routinely sent to AI APIs during normal agent workflows.
The strongest layer for Claude Code. Anthropic-shaped API calls routed through ANTHROPIC_BASE_URL pass through a local proxy that scans and redacts supported secrets before they leave your machine.
# One command — starts proxy, launches agent, cleans up on exit
pastewatch-cli launch claude
# With audit logging
pastewatch-cli launch --audit-log /tmp/pw-proxy.log -- claudeThis is the default way to run Claude Code with pastewatch. The launch command starts the proxy, sets ANTHROPIC_BASE_URL, runs the agent, and stops the proxy on exit.
Why this matters: Claude Code subprocesses (subagents, background workers, parallel tasks) can bypass tool-level protections like hooks and MCP. The proxy operates at the network boundary for supported Anthropic-shaped traffic, while hooks and MCP remain necessary defense in depth.
Corporate environments with mandatory company proxies:
# Pastewatch sits between the agent and the corporate proxy
pastewatch-cli launch --forward-proxy http://proxy.corp:8080 -- claudeThe agent connects to pastewatch as if it were the company proxy. Pastewatch scans, redacts, and forwards to the real proxy. Transparent to both the agent and the corporate network.
For manual control (separate terminals), use pastewatch-cli proxy directly:
# Terminal 1
pastewatch-cli proxy --audit-log /tmp/pw-proxy.log
# Terminal 2
ANTHROPIC_BASE_URL=http://127.0.0.1:8443 claudeThe most effective defense. If secrets aren't in files, they can't leak.
- Use
.envfiles (gitignored) for local development - Use vault references or config templates with placeholders in committed code
- Use environment variables in CI/CD pipelines
Verify before starting an agent session:
pastewatch-cli scan --dir . --checkFix findings first. Move hardcoded secrets to environment variables or vault references.
For files that must contain secrets (legacy code, config files being migrated), use pastewatch MCP tools. The MCP server sits between the agent and your files:
Your machine (local)
┌─────────────────────────────────────────────┐
│ │
│ pastewatch MCP server │
│ ┌───────────────────────────────────────┐ │
│ │ read_file: │ │
│ │ file (real secrets) │ │
│ │ → scan → store mapping in RAM │ │
│ │ → return content with │ │
│ │ __PW_EMAIL_1__ placeholders ──┼──┼──► AI API (sees only placeholders)
│ │ │ │
│ │ write_file: │ │
│ │ content with placeholders ◄─┼──┼─── AI API returns code
│ │ → resolve from RAM mapping │ │ (contains placeholders)
│ │ → write real values to disk │ │
│ └───────────────────────────────────────┘ │
│ │
│ Secrets never leave this box. │
└─────────────────────────────────────────────┘
Install pastewatch:
brew install ppiankov/tap/pastewatchFor per-agent registration instructions (Claude Code, Claude Desktop, Cline, Cursor, OpenCode, Codex CLI, Qwen Code), see agent-setup.md.
Once configured, the agent has access to these MCP tools:
| Tool | Purpose |
|---|---|
pastewatch_read_file |
Read file with secrets replaced by __PW_EMAIL_1__ placeholders |
pastewatch_write_file |
Write file, resolving placeholders back to real values locally |
pastewatch_check_output |
Verify text contains no raw secrets before returning |
Round-trip workflow:
- Agent calls
pastewatch_read_filefor sensitive files - Gets back content with
__PW_CREDENTIAL_1__,__PW_AWS_KEY_1__etc. - API processes code - only sees placeholders, never real secrets
- Agent calls
pastewatch_write_file- MCP server resolves placeholders on-device - Written file contains real values - code stays functional
What the agent sees (sent to API):
database:
host: db.internal.corp
port: 5432
password: __PW_CREDENTIAL_1__
api_key: __PW_AWS_KEY_1__What gets written to disk:
database:
host: db.internal.corp
port: 5432
password: (original secret restored)
api_key: (original key restored)pastewatch_read_file accepts an optional min_severity parameter (default: high). Only findings at or above the threshold are redacted - everything below passes through unchanged.
What gets redacted at each threshold:
min_severity |
Redacted | Passes through |
|---|---|---|
critical |
AWS keys, API keys, DB connections, SSH keys, JWTs, cards, webhooks | Credentials, emails, phones, IPs, hostnames, UUIDs |
high (default) |
All critical + credentials, emails, phones | IPs, hostnames, file paths, UUIDs |
medium |
All high + IPs, hostnames, file paths | UUIDs, high entropy |
low |
Everything | Nothing |
Example: .env file read with default min_severity: "high"
Original file contains AWS keys, a database URL, an API token, an IP address, and an internal hostname. After redaction with the default high threshold:
# What the agent sees (sent to API)
AWS_ACCESS_KEY_ID=__PW_AWS_KEY_1__ # critical - redacted
DATABASE_URL=__PW_DB_CONNECTION_1__ # critical - redacted
API_TOKEN=__PW_OPENAI_KEY_1__ # critical - redacted
ANSIBLE_HOST=172.16.161.206 # medium - passes through
INTERNAL_SERVER=keeper2.ipa.local # medium - passes throughThe IP and hostname pass through because they are medium severity - below the default high threshold. To redact them too, pass min_severity: "medium":
# With min_severity: "medium" - IPs and hostnames also redacted
AWS_ACCESS_KEY_ID=__PW_AWS_KEY_1__
DATABASE_URL=__PW_DB_CONNECTION_1__
API_TOKEN=__PW_OPENAI_KEY_1__
ANSIBLE_HOST=__PW_IP_1__ # medium - now redacted
INTERNAL_SERVER=__PW_HOSTNAME_1__ # medium - now redactedThe default high threshold is intentional - it protects credentials (the highest-damage leak vector) while keeping infrastructure identifiers readable so the agent can reason about architecture.
Different agents may need different thresholds. Use --min-severity on the MCP server command to set each agent's default independently:
{
"mcpServers": {
"pastewatch": {
"command": "pastewatch-cli",
"args": ["mcp", "--audit-log", "/tmp/pastewatch-audit.log", "--min-severity", "medium"]
}
}
}Precedence chain: per-request min_severity parameter > --min-severity CLI flag > mcpMinSeverity config field > default (high).
This means you can run Claude Code at high (default) and Cline at medium - each MCP registration controls its own threshold, and each agent can still override per-request when needed.
Enable audit logging to get proof of what the MCP server did during a session:
{
"mcpServers": {
"pastewatch": {
"command": "pastewatch-cli",
"args": ["mcp", "--audit-log", "/tmp/pastewatch-audit.log"]
}
}
}The log records every tool call with timestamps - what files were read, how many secrets were redacted, what types were found, how many placeholders were resolved on write. Secret values are never logged.
2026-02-25T00:30:12Z READ /app/config.yml redacted=3 [AWS Key, Credential, Email]
2026-02-25T00:30:15Z WRITE /app/config.yml resolved=3 unresolved=0
2026-02-25T00:30:18Z CHECK (inline) clean=true
- The MCP tools are opt-in - the agent must choose to use them
- Built-in Read/Write tools still bypass pastewatch unless hooks enforce it (see Layer 2b)
- Mappings live in server process memory only - die when MCP server stops
- Same file re-read returns the same placeholders (idempotent within session)
MCP tools are opt-in - agents can still use native Read/Write and cat .env via Bash, bypassing redaction entirely. Hooks make enforcement structural.
The guard subcommand intercepts shell commands before execution:
pastewatch-cli guard "cat .env"
# BLOCKED: .env contains 3 secret(s) (2 critical, 1 high)
# Use pastewatch MCP tools for files with secrets.
pastewatch-cli guard "echo hello"
# exit 0 (safe)It parses shell commands (cat, head, tail, sed, awk, grep, source), extracts file arguments, and scans those files for secrets. Unknown commands pass through (exit 0).
Integrate with agent Bash hooks to block commands automatically. See agent-setup.md for hook configuration per agent.
PW_GUARD=0 is a native feature of pastewatch-cli. When set, guard and scan --check exit 0 immediately - every hook that calls pastewatch-cli gets the bypass for free.
export PW_GUARD=0 # disable for current shell session
unset PW_GUARD # re-enableThis is agent-proof by design: the guard runs in the hook's process, not the agent's shell. The agent cannot set PW_GUARD=0 to bypass it - only the human can, before starting the agent session. The bypass requires human action outside the agent's control.
Use it when editing detection rules, working with test fixtures, or handling files with intentional secret-like patterns.
Limit which files the agent can read. Fewer files exposed = fewer secrets at risk.
Claude Code - .claude/settings.json:
{
"permissions": {
"deny": [
"Read(path:**/.env*)",
"Read(path:**/credentials*)",
"Read(path:**/secrets/**)"
]
}
}General principle: Keep secrets in dedicated directories or files with predictable names. Restrict agent access to those paths.
Catches secrets before they're committed - including secrets an agent may have written into code.
# Install pastewatch pre-commit hook
pastewatch-cli hook install
# Or use pre-commit.com framework
# .pre-commit-config.yaml
repos:
- repo: https://github.com/ppiankov/pastewatch
rev: v0.36.1
hooks:
- id: pastewatchThis catches cases where:
- An agent writes a new secret into code
- An agent copies a secret from one file to another
- Config changes accidentally expose credentials
Before starting an agent session on a project:
# Full scan
pastewatch-cli scan --dir . --check
# Only fail on critical (API keys, credentials, connection strings)
pastewatch-cli scan --dir . --check --fail-on-severity critical
# Detailed report
pastewatch-cli scan --dir . --format markdown --output /tmp/scan-report.mdFix findings before the agent reads them. The cheapest secret to protect is the one that's not in a file.
Add to .zshrc or .bashrc to run a health check before every agent session:
alias claude='pastewatch-cli doctor --json >/dev/null 2>&1 && command claude'This verifies pastewatch is installed, MCP is configured, and config is valid before the agent starts. If doctor fails, the session won't launch — fail-closed instead of fail-open.
For projects with known historical secrets that can't be cleaned up immediately:
# Create baseline of current findings
pastewatch-cli baseline create --dir . --output .pastewatch-baseline.json
# Only flag new secrets (ignore baseline)
pastewatch-cli scan --dir . --baseline .pastewatch-baseline.json --checkThis lets you adopt agent safety incrementally without blocking work on legacy codebases.
| Layer | What it does | Effort |
|---|---|---|
| 1. No secrets in code | Eliminate the source | High (best ROI) |
| 2. MCP redacted read/write | Secrets stay local during agent sessions | Low (configure once) |
| 2b. Enforce via hooks | Block native Read/Write/Bash when secrets present | Low (configure once) |
| 3. Restrict file access | Limit agent's blast radius | Low |
| 4. Pre-commit hook | Catch secrets before commit | Low (one-time setup) |
| 5. Pre-session scan | Find secrets before agent reads them | Per-session |
| 6. Baseline | Gradual cleanup of legacy codebases | Per-project |
Layers are additive. Use as many as your threat model requires. Layer 2 (MCP redacted read/write) is the most impactful for active agent workflows.
Pastewatch protects credentials - the highest-damage leak vector. If a key leaks, attackers get immediate access to infrastructure. Pastewatch prevents this structurally.
What pastewatch protects (secrets never leave your machine):
| Category | Examples |
|---|---|
| API keys | AWS, OpenAI, Anthropic, Stripe, GitHub tokens, etc. |
| Database credentials | Connection strings, passwords in config files |
| SSH/TLS keys | Private key headers |
| Identity data | Emails, phone numbers, IPs |
| Session tokens | JWTs, bearer tokens |
| Platform credentials | Slack/Discord webhooks, Azure/GCP keys |
What pastewatch does NOT protect:
| Category | Why |
|---|---|
| Prompt content | Your questions and instructions still reach the API |
| Code structure | Architecture, patterns, business logic - visible to the provider |
| Conversation context | What you're building, for whom, why |
| Non-secret data | Domain names, file paths, comments, variable names |
Pastewatch protects your keys. For protecting your ideas, you need a local model (Ollama, llama.cpp). For protecting your commands, you need a local proxy (intercepting before they reach the API).
Think of it as: secrets are the highest-consequence leak - a leaked API key has immediate, measurable damage. Pastewatch eliminates that risk. The other risks (prompt content, business logic) are real but require different tools.