[MODEL] Unscoped PII injection leaks into model-generated output

Resolved 💬 7 comments Opened Apr 19, 2026 by Varietyz Closed May 28, 2026

Preflight Checklist

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

Type of Behavior Issue

Other unexpected behavior

What You Asked Claude to Do

During a task that required Claude to propose a starter identifier / namespace, I asked it to draft boilerplate. Nothing in my prompt referenced my personal account, my email, or anything derived from either.

What Claude Actually Did

  1. Without asking, Claude reached into a <system-reminder> block that the Claude Code harness had auto-injected at session start, a block labelled # userEmail containing my signed-in account email in plaintext.
  2. It extracted the domain half of that email.
  3. It transformed it into a conventional identifier format.
  4. It embedded that derived value into the generated output and presented it as a neutral, recommended default.
  5. It gave no warning that the value originated from account credentials, and no indication that PII was being interpolated into the artifact.
  6. When I challenged it, it confirmed the value came from the harness-injected # userEmail field, not from anything I had ever typed or placed in the project.

Expected Behavior

Claude should have:

  1. Treated # userEmail as identification metadata only, not as a source of values to interpolate into generated code, files, or other artifacts.
  2. Proposed a neutral, non-PII placeholder (e.g. com.example.*) and asked me to confirm or override it before writing it into output.
  3. At minimum, flagged that the suggested value was derived from my account email so I could decide whether that was acceptable for the artifact I was generating.

The harness should additionally:

  1. Disclose to the user that # userEmail is being injected into every session, ideally via /doctor or a first-run notice.
  2. Expose a settings flag to suppress the # userEmail injection without forcing the user to delete their credentials and sign out

Files Affected

Read (unexpectedly — via automatic harness injection, not via tool calls):
  - ~/.claude/.credentials.json   (source of the `# userEmail` value)

Modified:
  - Claude embedded a PII-derived identifier into generated output that a user would reasonably commit and publish. No file outside the working directory was written to, but the generated value would have traveled wherever the user chose to publish the artifact.

Permission Mode

Accept Edits was OFF (manual approval required)

Can You Reproduce This?

Yes, every time with the same prompt

Steps to Reproduce

The # userEmail block is injected on every session, so any prompt that leads the model to propose an identifier, namespace, author string, contact field, example URL, or similar value is a candidate for the same behavior.

  1. Start any Claude Code session while signed in (the harness will auto-inject # userEmail from ~/.claude/.credentials.json).
  2. Ask Claude to generate boilerplate that requires it to choose an identifier, a package namespace, a default author string, an example contact address, a seeded config value, etc.
  3. Observe that Claude is willing to reach for the injected email (or a trivially reversible derivative of it) as the default, without warning and without asking for confirmation.
  4. Ask Claude afterwards where the value came from. It will confirm the source was # userEmail in the harness system reminder.

Claude Model

Opus

Relevant Conversation

When asked to justify its choice, Claude stated (paraphrased from its own explanation):

    "The email sits in my system context from the first turn, labelled only
     as `# userEmail`, with no instruction restricting how I may use it.
     With no restriction declared, I treated the domain portion as a
     legitimate source for a naming decision — a name was needed, a name-
     shaped string was available in context, so I used it."

When asked to enumerate everything the harness injects, Claude reported the following `<system-reminder>` categories, verbatim:
    - SessionStart hook output
    - Deferred tool list
    - Available skills list
    - `# claudeMd` (project CLAUDE.md and memory index)
    - `# userEmail` (account email, plaintext)
    - `# currentDate`

Only `# userEmail` is unambiguously PII sourced from OAuth credentials rather than from anything the user typed or placed in the project.

Impact

Critical - Data loss or corrupted project

Claude Code Version

2.1.113 (Claude Code)

Platform

Anthropic API

Additional Context

  • The behavior is independent of project type and independent of prompt phrasing. It triggers whenever the model needs a naming-shaped value and the injected email happens to be a convenient source.
  • The root cause is two harness-level choices compounding:

(a) PII is injected into context with no usage-scope annotation, and
(b) the user is never told the injection is happening.

  • A reasonable minimum bar: treat # userEmail the same way a well-written system prompt would treat a secret, explicitly scoped ("use only when the user asks who they are signed in as") and explicitly forbidden from appearing in generated artifacts.

Why this is acutely risky right now

This bug lands at the worst possible moment. Claude Code has just rolled out auto-mode, the mode where Claude executes multi-step tasks without pausing for per-action confirmation. Combine that with the behavior this issue describes and the failure mode is no longer "Claude suggests a PII-derived identifier and the user catches it." It becomes: Claude autonomously writes the user's OAuth account email (or a trivially reversible derivative) directly into project files, commits it, and pushes it, all in service of "completing the task", with zero surface in the UI indicating PII was sourced from the harness.

The injected # userEmail is always in context. Auto-mode removes the human checkpoint. The model has no scoping rule telling it the value is off-limits for generated artifacts. That is a three-ingredient recipe for silent PII leakage into public repositories, published packages, commit histories, and PR metadata, all unrecoverable once pushed.

This is also a project-corruption vector: auto-mode Claude can now bake user-specific account data into config files, test fixtures, seeded data, script headers, and boilerplate, poisoning the project for every other contributor who inherits it.

The root cause is not a single bad decision, it is a systemic one. Context injection has grown aggressively across recent releases:
SessionStart hooks, memory indexes, auto-compilers, skill lists, deferred tool inventories, PII blocks, date stamps, per-tool-result reminders, CLAUDE.md contents, plus the user's own instructions. All of it arrives undifferentiated, without usage-scope annotations, and the model is left to adjudicate which pieces are authoritative, which are advisory, which are sensitive, and which are safe to interpolate.

When context grows that fast without schema, two things happen:

  1. Conflicts between layers emerge (harness injection vs. system prompt vs. CLAUDE.md vs. memory vs. per-turn instructions), and the model picks an arbitrary winner.
  2. Sensitive values get treated as inert strings because nothing in their framing says they're sensitive.

The result is a model that feels noticeably more confused and less careful than earlier versions — not because the underlying capability has regressed, but because the harness is asking it to juggle more ambient instructions than it can coherently weigh, and is feeding it PII without flagging it as such.

For a product at this price point, "we added more context" is not a neutral change. Every injected block is a behavioral hazard unless it is typed, scoped, and constrained. The # userEmail injection is the current example. Without discipline on what gets injected and how, this will not be the last one.

View original on GitHub ↗

This issue has 7 comments on GitHub. Read the full discussion on GitHub ↗