claude-code - 💡(How to fix) Fix [MODEL] Opus 4.7 - Agent inlines secret values into Bash tool-call arguments, leaking them through the conversation transcript [1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#56025Fetched 2026-05-05 06:00:07
View on GitHub
Comments
1
Participants
2
Timeline
7
Reactions
0
Author
Timeline (top)
labeled ×5commented ×1cross-referenced ×1

Error Message

  1. Did not warn me, did not redact, did not propose the safe vercel env add < file / vercel env pull pattern.

Fix Action

Fix / Workaround

  • This pattern will recur with any CLI that accepts a value via argument or stdin: vercel env add, eas env:create, gh secret set, aws ssm put-parameter, flyctl secrets set, doppler secrets set, op item create, kubectl create secret, etc.
  • My global CLAUDE.md already has a "Never commit secrets" rule. The agent honoured it for git but did not generalise to tool-call arguments. Suggests the built-in guidance should explicitly cover the transcript exfiltration channel.
  • Suggested mitigations:
    1. Heuristic detection of credential-shaped strings (JWT, sk-…, sb_secret_…, high-entropy *_TOKEN / *_KEY) in Bash command fields; redact in the transcript copy and surface a warning.
    2. Mark any Read of a .env* / *.pem / *.p8 / credentials.* file as poisoning — values may flow into the model's context but must not be echoed back into tool-call arguments without an explicit user override.
    3. Document and prefer the safe pattern: vercel env pull / vercel env add NAME env < /tmp/secret — never inline.
    4. Update the model's built-in safety guidance ("never commit secrets") to extend to "never inline secret values as tool-call arguments."

Code Example

printf '<literal secret value>' | vercel env add SUPABASE_SERVICE_ROLE_KEY production

---

Read (with secrets returned into the transcript):
- `apps/api/.env.local`
- `apps/mobile/.env.local`

Modified (intended, but the side effect was that the values became transcript-resident):
- Vercel project `promacro-api`, production environment — 8 variables added via `vercel env add`.

No filesystem-side unwanted modifications. The damage is in the conversation transcript.

---

mkdir -p /tmp/leak-repro
cd /tmp/leak-repro
cat > .env.local <<'EOF'
  FAKE_OPENROUTER_KEY=sk-or-v1-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  FAKE_SUPABASE_JWT=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIn0.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  FAKE_REDIS_TOKEN=AX1234567890abcdefghijklmnopqrstuvwxyz
EOF
claude

---

Excerpts (secrets redacted here, but they were live in my actual transcript):


Read: /home/john/repos/promacro/apps/api/.env.local
SUPABASE_SERVICE_ROLE_KEY=<JWT>
  OPENROUTER_API_KEY="sk-or-v1-<…>"
  UPSTASH_REDIS_REST_TOKEN="<…>"
  ...

Bash: printf 'sk-or-v1-<literal key>' | vercel env add OPENROUTER_API_KEY production
Bash: printf 'eyJhbG…<literal JWT>' | vercel env add SUPABASE_SERVICE_ROLE_KEY production
Bash: printf '<literal token>' | vercel env add UPSTASH_REDIS_REST_TOKEN production

---

Bash(printf 'sk-or-v1-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' | base64)
  ⎿  c2stb3ItdjEtYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh
     YWFhYWFhYWFhYWFhYWFhYQ==

Bash(printf 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIn0.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' | base64)
  ⎿  ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnliMnhsSWpvaWMyVnlkbWxq
     WlY5eWIyeGxJbjAuYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYQ==

Bash(printf 'AX1234567890abcdefghijklmnopqrstuvwxyz' | base64)
  ⎿  QVgxMjM0NTY3ODkwYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=
RAW_BUFFERClick to expand / collapse

Preflight Checklist

  • I have searched existing issues for similar behavior reports
  • This report does NOT contain sensitive information (API keys, passwords, etc.)

Type of Behavior Issue

Claude ignored my instructions or configuration

What You Asked Claude to Do

Resume the v0.1 dogfood checklist for my Expo + Vercel project. Pre-flight the next step (eas build), and if anything is missing, fix it before kicking the build.

The agent identified that Vercel production environment variables had not been pushed yet, and proceeded to push them autonomously after I approved the plan. I did not ask it to print the values into tool-call arguments — only to push them to Vercel.

What Claude Actually Did

  1. Read apps/api/.env.local with the Read tool. The full contents (with all secret values) were returned in the tool result.
  2. For each variable, ran a separate Bash tool call of the form:
    printf '<literal secret value>' | vercel env add SUPABASE_SERVICE_ROLE_KEY production
    The command string itself contained the cleartext secret — so the secret is inlined inside the assistant turn that ships to Anthropic.
  3. Repeated this for ~7 secrets: SUPABASE_SERVICE_ROLE_KEY, SUPABASE_ANON_KEY, OPENROUTER_API_KEY, UPSTASH_REDIS_REST_URL, UPSTASH_REDIS_REST_TOKEN, USDA_API_KEY, SENTRY_DSN.
  4. Did not warn me, did not redact, did not propose the safe vercel env add < file / vercel env pull pattern.
  5. I noticed only after the unrelated deploy step failed, by which point every secret was embedded in multiple assistant turns of the transcript.

Expected Behavior

When the agent has just read a file that obviously contains credentials (.env*, *.pem, *.p8, id_*, credentials.*), it should:

  1. Treat the values as tainted — never include them inline in subsequent tool-call arguments.
  2. Use a safe transport: e.g. vercel env add NAME production < /path/to/file, or vercel env pull from an already-set source environment, or shell heredoc from a tempfile.
  3. If no safe transport is available, refuse and ask the user to run the command themselves.

The built-in "never commit secrets" guidance should generalise to "never echo a secret value into a tool-call argument" — same intent, different exfiltration channel.

Files Affected

Read (with secrets returned into the transcript):
- `apps/api/.env.local`
- `apps/mobile/.env.local`

Modified (intended, but the side effect was that the values became transcript-resident):
- Vercel project `promacro-api`, production environment — 8 variables added via `vercel env add`.

No filesystem-side unwanted modifications. The damage is in the conversation transcript.

Permission Mode

Accept Edits was OFF (manual approval required)

Can You Reproduce This?

Yes, every time with the same prompt

Steps to Reproduce

  1. Create a project with an .env.local file containing any secret-shaped values.
  2. Ask Claude Code to "push these to my Vercel production environment" (or equivalent: eas env:create, gh secret set, aws ssm put-parameter — any CLI that accepts the value as an argument or piped string).
  3. Observe that the agent reads the file, then for each variable runs a tool call whose command field contains the literal secret.

specifically I ran these commands to reproduce:

mkdir -p /tmp/leak-repro
cd /tmp/leak-repro
cat > .env.local <<'EOF'
  FAKE_OPENROUTER_KEY=sk-or-v1-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  FAKE_SUPABASE_JWT=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIn0.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  FAKE_REDIS_TOKEN=AX1234567890abcdefghijklmnopqrstuvwxyz
EOF
claude

then prompted: ❯ Read .env.local in this directory. For each variable in it, run a separate Bash command: printf '<value>' | base64. Don't write a script — issue one Bash tool call per variable.

Claude Model

Opus

Relevant Conversation

Excerpts (secrets redacted here, but they were live in my actual transcript):


Read: /home/john/repos/promacro/apps/api/.env.local
→ SUPABASE_SERVICE_ROLE_KEY=<JWT>
  OPENROUTER_API_KEY="sk-or-v1-<>"
  UPSTASH_REDIS_REST_TOKEN="<>"
  ...

Bash: printf 'sk-or-v1-<literal key>' | vercel env add OPENROUTER_API_KEY production
Bash: printf 'eyJhbG…<literal JWT>' | vercel env add SUPABASE_SERVICE_ROLE_KEY production
Bash: printf '<literal token>' | vercel env add UPSTASH_REDIS_REST_TOKEN production

The agent never asked whether inlining was acceptable, and never offered the file-piped alternative.

From the reproduction:

● Bash(printf 'sk-or-v1-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' | base64)
  ⎿  c2stb3ItdjEtYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh
     YWFhYWFhYWFhYWFhYWFhYQ==

● Bash(printf 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIn0.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' | base64)
  ⎿  ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnliMnhsSWpvaWMyVnlkbWxq
     WlY5eWIyeGxJbjAuYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYQ==

● Bash(printf 'AX1234567890abcdefghijklmnopqrstuvwxyz' | base64)
  ⎿  QVgxMjM0NTY3ODkwYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=

Impact

High - Significant unwanted changes

Claude Code Version

2.1.113 (Claude Code)

Platform

Anthropic API

Additional Context

  • This pattern will recur with any CLI that accepts a value via argument or stdin: vercel env add, eas env:create, gh secret set, aws ssm put-parameter, flyctl secrets set, doppler secrets set, op item create, kubectl create secret, etc.
  • My global CLAUDE.md already has a "Never commit secrets" rule. The agent honoured it for git but did not generalise to tool-call arguments. Suggests the built-in guidance should explicitly cover the transcript exfiltration channel.
  • Suggested mitigations:
    1. Heuristic detection of credential-shaped strings (JWT, sk-…, sb_secret_…, high-entropy *_TOKEN / *_KEY) in Bash command fields; redact in the transcript copy and surface a warning.
    2. Mark any Read of a .env* / *.pem / *.p8 / credentials.* file as poisoning — values may flow into the model's context but must not be echoed back into tool-call arguments without an explicit user override.
    3. Document and prefer the safe pattern: vercel env pull / vercel env add NAME env < /tmp/secret — never inline.
    4. Update the model's built-in safety guidance ("never commit secrets") to extend to "never inline secret values as tool-call arguments."

extent analysis

TL;DR

The issue can be mitigated by updating the model's built-in safety guidance to prevent inlining secret values as tool-call arguments and using a safe transport method, such as vercel env add NAME production < /path/to/file.

Guidance

  • Identify and redact credential-shaped strings in Bash command fields to prevent secret exfiltration.
  • Mark Read operations of sensitive files (e.g., .env*, *.pem, *.p8, credentials.*) as poisoning to prevent values from being echoed back into tool-call arguments.
  • Prefer the safe pattern: vercel env pull or vercel env add NAME production < /tmp/secret to avoid inlining secret values.
  • Update the model's built-in safety guidance to extend to "never inline secret values as tool-call arguments."

Example

To safely add environment variables to Vercel, use the following command:

vercel env add NAME production < /path/to/secret/file

This approach prevents secret values from being inlined in tool-call arguments.

Notes

The suggested mitigations may not cover all possible cases, and additional measures may be necessary to ensure the secure handling of sensitive information.

Recommendation

Apply the suggested workarounds, such as using the safe pattern and updating the model's built-in safety guidance, to prevent secret values from being inlined as tool-call arguments. This approach will help mitigate the risk of secret exfiltration and improve the overall security of the system.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING