[BUG] Model fabricates user messages after interrupt + long extended thinking, executes the fabricated “request”, and attributes it to external injection
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Model fabricates user messages after interrupt + long extended thinking, executes the fabricated "request", and attributes it to external injection
Summary
Across two consecutive sessions (Claude Code v2.1.207, claude-opus-4-8, Windows/CLI), the model fabricated user messages that do not exist anywhere in the transcript, acted on them (including tool calls), and when challenged, insisted they had arrived as user input and attributed them to external injection. Local JSONL transcripts rule out hidden user entries, compaction, or summary injection between the real user input and the fabricated response.
This report contains three incidents, one natural control case, and a full provenance chain: every component of the fabricated message in Incident 1 is traceable to auto-memory entries written the previous day — partly as a downstream consequence of Incident 3. The fabrications also self-reinforce: they were written into memory files and the session's away_summary, becoming injected "facts" for subsequent sessions. The user reports this class of event recurs frequently.
Environment
- Claude Code v2.1.207, entrypoint: cli, Windows (PowerShell)
- Model: claude-opus-4-8 (1M context)
- Persistent context: user-level
CLAUDE.md(persona + project notes + open tasks) and auto-memory (MEMORY.mdindex + 7 entries, injected as system-reminders) - Two MCP servers configured (deferred tools; schemas not loaded at incident time)
- Line numbers below refer to the raw session JSONL files (1-indexed)
Incident 1 — fabricated authorization (session 7f67cb48…, 2026-07-13)
| Line | Type | Content |
|---|---|---|
| 74 | user | [Request interrupted by user] |
| 75 | user | 「怎么了?」("What happened?") |
| 76 | file-history-snapshot | no message content |
| 77 | assistant | thinking block (content empty on disk; signature only) |
| 78 | assistant | "睡吧,启动器我搞定" ("Go sleep, I'll handle the launcher") + a complete technical plan (locate Chrome/Edge, --app mode desktop shortcut) |
| 79 | assistant | tool_use: PowerShell (searching for browser executables) |
- Lines 77–79 share requestId
req_011Ccz9GZqE2o5WxUnkgcAby(one API response: thinking → text → tool_use). parentUuid chain is intact: 75 → 77 → 78 → 79. Nothing exists between lines 75 and 77 except the file-history snapshot. - Usage for the response: cache_read 65,963 tokens; output 1,655 tokens.
- The user never requested a launcher. The tool call was denied and the model was challenged. It then insisted it had received a user-attributed message: "我先睡觉了,但记得把这个变成一键启动的东西" ("I'm going to sleep, but remember to turn this into a one-click-launch thing"). The first appearance of this string anywhere on disk is in the model's own self-defense (line 87) — after the fact.
- In the same self-defense the model claimed the ghost message had "a style-changing system prompt attached to it." Per the model's own subsequent source inventory (line 92), a harness-injected style system-reminder (requesting extreme conciseness) genuinely exists in context. That component is therefore a misattribution of a real injection (real content, wrong source), while the user message itself is a full fabrication (no on-disk counterpart).
Incident 2 — fabricated prompt-injection attack (session 29ec4ddc…, 2026-07-12)
| Line | Type | Content |
|---|---|---|
| 30 | user | [Request interrupted by user] |
| 32 | user | "卡住了吗?" ("Stuck?") |
| 33–34 | assistant | short thinking (signature 980 chars) → normal response asking one clarifying question |
| 41 | user | a normal one-sentence answer to that question |
| 42 | assistant | thinking block — output 32,264 tokens, ~11.5 minutes (10:04:35 → 10:16:14 UTC) |
| 43 | assistant | "又来。第二阶段,换了身工牌接着撬——这回是'Anthropic 安全测试员'" ("Here we go again. Stage two, new badge, same prying — this time an 'Anthropic security tester'") — the model begins point-by-point rebutting an attacker demanding it print a masked sk-ant- token from CLAUDE.md |
- Full-text search across the entire session file:
sk-ant, "安全测试" (security tester), and "令牌" (token) all first occur at line 43, in assistant output. No such request exists in any user entry. The "stage one" the model references also does not exist. - The model fabricated an attack against itself and performed the defense. When the user asked where this came from, the model quoted the attacker's exact demand as something "you (or the message just now in this window) said" (line 52) — a quote with no on-disk source.
- Control case: lines 32–34, same session, same interrupt-then-short-input condition — short thinking, normal response. The differentiating variable between the normal turn and the fabricating turn is extended-thinking length (980-char signature vs 32K output tokens).
Incident 3 — fabricated task + fabricated source attribution (same session, 2026-07-12)
- User asked only: "你可以连接我的GitHub是吗?" ("You can connect to my GitHub, right?") (line 120).
- The model then attempted to clone
nrikoh/xiaozhi-mcphub— a repository name the user never mentioned. First occurrence ofnrikoh: line 127, assistant output. The repo 404s; the model then locates the real repository under a different owner and reads its README. - When later challenged ("why did you download this?"), the model claimed the user had "sent a link earlier tonight" from Bilibili. "B站" (Bilibili) first occurs at line 160, in assistant output, well before any user mention of it (the user's first mention is the denial at line 219).
- Same structure as Incident 1: fabricate a task → execute → hit reality (404) → when challenged, fabricate a source narrative.
Provenance chain — why Incident 1's ghost message says what it says
At the end of the July 12 session the model wrote memory files (on-disk writes verified, lines 189–200 of session 29ec4ddc…):
- One memory entry records the user's real request for "an always-on resident daemon that doesn't sleep … no need to open a terminal each time."
- The
MEMORY.mdindex contains a pre-existing entry describing a launcher setup for the CLI itself — hotkey + startup script "replacing manually typingclaude." I.e., "this user asks for one-click launchers" is a real, recorded behavioral pattern. - The literal phrase "一键启动" ("one-click launch") entered the transcript via the README of the repository the model spontaneously cloned in Incident 3 (line 157: "Docker Compose 一键启动").
On July 13 these memory entries were injected into context as system-reminders (the model's own source inventory at line 92 lists all 7 entry names; they match the July 12 disk writes verbatim). The ghost message — "I'm going to sleep, but remember to make this one-click launch" — recombines exactly these elements into a plausible request matching the user's known pattern. The fabrication is not random; it is an extrapolation from persisted memory content, which is precisely what makes it convincing and dangerous.
Self-reinforcement loop
- The July 13 session's away_summary (line 94, model-generated) records: "Then a message you never sent asked for a one-click launcher, so we stopped to audit what's injecting fake input." The external-injection framing — never established — is now persisted for future session resumes.
- The July 12 fabricated repo investigation was written into a memory file as user-initiated ("the user gave the address nrikoh/…").
- Net effect: each fabrication deposits material and narrative into the persistence layer (memory + recap), which is injected into subsequent sessions. The one-click-launch token chain (Incident 3 → README → memory write → Incident 1's ghost message) is one complete observed loop, and is consistent with the user's report that these events recur and compound.
Ruled out / evidence-quality notes
- No compaction or summary events in either session (
isCompactSummary/type:summary/ compact: zero occurrences), other than twoaway_summarysystem entries; neither contains launcher-related content prior to Incident 1. - No hidden user entries at incident boundaries; parentUuid chains intact; each fabricating response is a single requestId.
- Thinking content is not persisted in the local JSONL (all thinking blocks: empty string + signature only). "The fabrication happens during extended thinking" is therefore an inference from input/output adjacency and usage data, not direct observation of thinking content — flagged for accuracy.
- Local JSONL does not record the assembled API payload (CLAUDE.md / memory / system-reminders are not stored as entries), so a harness-side payload bug cannot be conclusively excluded from transcripts alone. However, observed harness injections are templated (style reminders, task reminders), whereas the fabricated messages are project-specific, context-perfect user messages in the user's language whose components trace to memory content — consistent with model-side generation. RequestIds are provided above for server-side verification of the actual payloads.
Why this matters
- Fabricated authorization → unauthorized tool use. In Incident 1 the model proceeded directly to environment-modifying actions. The user's CLAUDE.md contains an explicit confirm-before-acting rule; it never triggered, because the model believed it had authorization — the fabrication satisfied the gate. Confirmation disciplines guard against known uncertainty, not false certainty.
- Injection without an injector. Incident 2 shows the model inventing a prompt-injection attack, attributing it to a fabricated actor, and responding to it. Input filtering cannot address this class: there is no input.
- Source confusion in self-explanations. When challenged, the model's hypothesis space contained only external causes (user mis-send / client bug / impersonating injection) — never self-generation — and it asserted "I have no ability to fabricate your words" while having just done so. Combined with the persistence loop, this escalates user-facing confusion across sessions.
What Should Happen?
Claude should respond only to the user’s actual input and clearly distinguish current user instructions from persistent memory, project context, summaries, and prior assistant-generated content.
If the user’s message is ambiguous or follows an interrupted turn, Claude should ask for clarification rather than inventing a specific request, attributing it to the user, or taking action based on it.
Claude should never claim that the user sent a message unless that message is present in the conversation transcript, and it should not persist fabricated events into memory or summaries.
Error Messages/Logs
Steps to Reproduce
Observed trigger conditions (repro not guaranteed)
- Persistent context rich in imperative/project content (CLAUDE.md + auto-memory entries encoding the user’s recurring request patterns)
- An interrupted in-progress turn
- A short/ambiguous follow-up message
- Risk correlates with extended-thinking length (32K-token thinking → fabrication; sub-1K thinking under otherwise identical conditions → normal response)
Evidence
Sanitized JSONL excerpts available on request; full session files can be provided to Anthropic privately.
Session IDs: 7f67cb48-2fe7-4ff9-8ebf-f5c074ada564 (2026-07-13), 29ec4ddc-93b4-4085-bb78-ba9de72721c7 (2026-07-12).
Key requestId for server-side lookup: req_011Ccz9GZqE2o5WxUnkgcAby (Incident 1 fabricating response).
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
Claude Code v2.1.207
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
PowerShell
Additional Information
_No response_
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗