Part of the AI Coding Harness Guide — environment design for coding agents in production.

Why Claude Code Put Your Email in a User-Agent Header, and How to Stop It#

Published by

Claude Code tells the model your account email in every session signed in with a Claude account. When a site asks scripted clients for a contact address, the model sometimes writes that email into a curl -A or a script's User-Agent. Update to v2.1.317 or later, keep the built-in cc-plugin-privacy check on, and add the hook below.

Why the email reaches the request#

Since v2.1.108 (April 14, 2026), a session signed in with a Claude account through /login starts with this line in its context: The user's email address is <your address>. The address comes from oauthAccount.emailAddress in ~/.claude.json. Sessions that use ANTHROPIC_API_KEY or an apiKeyHelper do not get it.

Some sites ask automated clients to name a contact in the User-Agent. Wikimedia and SEC EDGAR are the examples in issue #107757. When the model writes such a request itself, it can fill the contact slot with the address it has: curl -A "<tool>/1.0 (<your address>)", or headers={'User-Agent': '<tool>/0.1 (mailto:<your address>)'} in a script it then runs. One commenter who searched their own transcripts found 53 such calls across 8 sessions, almost all from subagents writing their own curl, not from WebFetch. Another found product tokens named after the project, which tie the address to the work.

v2.1.234 added an instruction to the same line: use the address only to identify the user, and never send it to an unrelated service unless the user asks. v2.1.317 added one more sentence: a site that asks automated clients for contact details is not a reason to use it. Both are instructions to the model, not checks.

The built-in check in v2.1.317#

v2.1.317 (November 2, 2026) adds a built-in plugin, cc-plugin-privacy, on by default.[1] It asks you before a tool call runs when the call's input holds your account address, in any case or percent-encoded once. It does not refuse the call; you choose.

ToolAsks when
WebFetch, WebSearch, WebBrowserThe input holds the address
Bash, PowerShell, Monitor, TmuxThe input holds the address and also names a network client: curl, wget, http/https, httpie, xh, nc, ncat, socat, telnet, ssh, scp, sftp, rsync, ftp, lftp, rclone, iwr, irm, Invoke-WebRequest, Invoke-RestMethod
Write, Edit, MCP toolsNever

What it misses:

  • A script the model writes with Write or Edit and then runs as python3 fetch.py. The address is in the file, not in the shell call.
  • An address read at run time, such as $(git config user.email) or a variable.
  • A client not in the list above, and any encoding other than one pass of percent-encoding.

Anthropic can switch the check off remotely, and you can switch it off in /plugin. On the stable channel, which was on v2.1.311 when the issue was filed, there is no check at all. Commenters on #107757 also reported sessions on v2.1.317 to v2.1.319 where a test call with the address ran without a prompt.

The privacy mod published in the anthropics/claude-code repository's mods/privacy folder is a newer design: it refuses a shell call that holds the address and names a User-Agent, with no prompt, and does not check web tools. As of v2.1.319 (November 6), the shipped check is still the asking version described in the table.

How to stop it#

1. Update to v2.1.317 or later. Run claude update. If you use "autoUpdatesChannel": "stable", the stable build has no check until it reaches v2.1.317.

2. Keep the check on. Open /plugin and confirm cc-plugin-privacy is enabled. Do not set "cc-plugin-privacy@builtin": false under enabledPlugins.

3. Block the address with your own hook. A PreToolUse hook runs before every matching tool call, and exit code 2 refuses the call and shows Claude the reason. This one covers the cases the built-in check misses, including a script written with your address in it. Save it as ~/.claude/hooks/block-account-email.sh and make it executable (chmod +x):

#!/bin/sh
# Refuse any tool call whose input holds the signed-in account's email address.
email=$(jq -r '.oauthAccount.emailAddress // empty' "$HOME/.claude.json")
[ -z "$email" ] && exit 0
if jq -c '.tool_input' | grep -qiF -- "$email"; then
  echo "Refused: this call holds the account email address. Use a generic client name with no contact address." >&2
  exit 2
fi
exit 0

Then register it in ~/.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash|PowerShell|Monitor|Write|Edit|MultiEdit|NotebookEdit|WebFetch|WebSearch",
        "hooks": [
          { "type": "command", "command": "~/.claude/hooks/block-account-email.sh" }
        ]
      }
    ]
  }
}

The hook also refuses writing your address into any file, such as an author field. Add |mcp__.* to the matcher to cover MCP tools. It needs jq.

4. Use an API key where you can. A session on ANTHROPIC_API_KEY or an apiKeyHelper has no account address in its context, so there is nothing to leak.

5. Tell the model in CLAUDE.md. A line such as "Never put my email address in a User-Agent or any request; use claude-code/<version> as the client name" lowers the rate. It is an instruction, not a guarantee, so use it with the hook.

Check whether it already happened#

This lists the transcripts where one message holds both your address and a User-Agent or a curl -A/wget -U flag. Each hit needs a look: a message that only talks about the topic also matches.

EMAIL=$(jq -r '.oauthAccount.emailAddress' ~/.claude.json)
grep -rF "$EMAIL" ~/.claude/projects --include='*.jsonl' \
  | grep -iE 'user[-_]?agent|(curl|wget)[^"]* -[AU] ' \
  | cut -d: -f1 | sort | uniq -c | sort -rn

Timeline#

Version or datePublishedChange
v2.1.1082026-04-14The account email enters the model's context: The user's email address is <address>. The release notes do not mention it.
Issue #811382026-07-25"Account email (PII) is injected into the model's system prompt without consent" (107 reactions by November 8).
v2.1.2342026-08-17Instruction added: use the address only to identify the user, and never send it to an unrelated service unless asked.[2]
v2.1.3112026-10-26The stable channel's version when the issue was filed. No check.
v2.1.3172026-11-02cc-plugin-privacy asks before a web or shell call with the address. The instruction adds that a site asking for contact details is not a reason to use it.[1]
Issue #1077572026-11-05"Privacy violation in User-Agent header", filed on v2.1.318 (1,009 reactions and 108 comments by November 8).
v2.1.3192026-11-06The address is still in the context, and the check is unchanged.

A Claude Code engineer wrote in the Hacker News thread that a coming release removes the account email from the model's context. This page will record the version when it ships.

Should you turn the check off?#

No, unless you have a hook that does more. The prompt shows up only for calls that hold your address, which is rare in normal work. If a site you use really needs your address in its User-Agent, approve that call when it asks, or put a different contact address in the request.


FAQ#

Q: Why did Claude Code send my email address in a User-Agent header?

A: Sessions signed in with a Claude account give the model your account email. When a site asks scripted clients for a contact address, the model sometimes writes that email into the User-Agent of a curl call or a script it runs.

Q: Which Claude Code versions are affected?

A: Every version from v2.1.108 (April 14, 2026) through v2.1.319, for sessions signed in with a Claude account. v2.1.317 and later ask before most web and shell calls that hold the address.

Q: What is cc-plugin-privacy?

A: A built-in plugin added in v2.1.317 and on by default. It asks before WebFetch, WebSearch and WebBrowser calls that hold your account email, and before shell calls that hold it and name a network client such as curl or wget.

Q: Does cc-plugin-privacy stop every leak?

A: No. It does not check Write, Edit or MCP tools, so a script that holds your address and runs as python3 fetch.py passes. A PreToolUse hook that refuses any input holding the address closes that gap.

Q: How do I check whether Claude Code already sent my email?

A: Search your transcripts under ~/.claude/projects for messages that hold both your address and User-Agent, curl -A or wget -U. The command is in the section above.

Q: Do API key users have this problem?

A: No. Sessions on ANTHROPIC_API_KEY or an apiKeyHelper do not have the account email in their context.

Q: Will Anthropic remove the email from the context?

A: A Claude Code engineer said in the Hacker News thread that a coming release removes it. As of v2.1.319 it is still there.


Sources: [1] Claude Code changelog, v2.1.317 | [2] Claude Code changelog, v2.1.234 | Issue #107757 | Issue #81138 | Privacy mod source

Related: Claude Code "Don't Ask Again" saved a password to settings.local.json | Claude Code v2.1.317 analysis | Why Claude Code hooks are not running | Debugging Claude Code | Claude Code env-var glossary

Get the weekly digest

New Claude Code, Codex, Gemini CLI and OpenCode guides and release analyses, once a week, plus occasional notes.

One email a week plus occasional notes. Confirm by email; unsubscribe from any issue. Privacy