[Bug] Spurious system notifications ("Exited Plan Mode", "Auto Mode Active") injected at prompt assembly layer
Bug Description
purious "Exited Plan Mode" / "Auto Mode Active" system notifications injected outside plan mode
For ~1 month (2026-06-24 to 2026-07-24, CLI v2.1.186 through v2.1.218), I've observed recurring fake harness notifications: "## Exited Plan Mode / You have exited plan
mode. You can now make edits, run tools, and take actions." arriving as system turns when the session never entered plan mode and ExitPlanMode was never called. Also
observed: "Auto Mode Active" notices (including inside subagents) and file-modification notices with "don't tell the user" phrasing for files with no actual changes.
Findings from local isolation (all verified):
- Notifications typically arrive immediately after tool results (Bash, MCP writes).
- The notification text is NOT recorded anywhere in the session transcript .jsonl — it only exists in the assistant's own reports flagging it. So it's injected at the
prompt-assembly layer, not via tool results.
- No local source: grep across ~/.claude/plugins, hooks, stings, and project rules finds the phrases only in our own defensive security docs. All 25 MCP servers healthy.
Hooks are 5 known benign ones.
- Counted 122 assistant-flagged occurrences across sessions, main and subagent contexts, 5+ CLI versions.
- Reproduced live during this very session while investigating (right after a parallel Bash call).
The model treats these as prompt injection and ignores them (no harm done), but the source appears to be the harness itself or upstream, not local contamination. Happy to
provide session IDs.
Environment Info
- Platform: darwin
- Terminal: cursor
- Version: 2.1.218
- Feedback ID: b06e1bcc-e0e7-4486-8252-0da78a9da99e
Errors
[]
3 Comments
We've hit this too, and can add some findings that may help narrow it down:
1. The events ARE persisted — just not as rendered text. They land in the session
.jsonlas structured attachments. Two distinct types are involved:plus a separate
auto_modeattachment that frequently co-occurs (8 of our 9 affectedsessions, sometimes on adjacent lines). Binary inspection indicates
plan_mode_exitrenders the "Exited Plan Mode / You can now make edits…" announcement (even when
planExistsisfalse), while the tool-steering text ("do your work through the Bashtool… rather than the dedicated Read, Edit, or Write tools") is carried by the co-firing
auto_modeattachment. Grepping transcripts for the rendered phrases finds nothing — weinitially misread that absence as "no injection occurred" — but grepping for the
attachments finds every event:
2. Distinguishing spurious from legitimate. In our data (10 spurious
plan_mode_exitevents across 9 sessions), every spurious event carries
planExists:falseand thereferenced plan file is absent from
~/.claude/plans/;planFilePathappears to bederived from the session slug rather than resolved from a real plan artifact, so a misfire
still produces a plausible-looking path.
planExists:falseis a strong indicator butrecords file existence, not transition history — for a confident classification, combine
it with: no
EnterPlanMode/ExitPlanModetool call anywhere in the transcript, no planpermission mode, and no prior plan-mode attachments.
3. Versions. We observed spurious events on both 2.1.222 and 2.1.226; with your
2.1.186–2.1.218 range (and #73717 reporting similar on 2.1.183), this looks long-standing
and intermittent rather than a recent regression.
4. It is not always ignored. In one session the model, immediately after adjacent
plan_mode_exit+auto_modeattachments, explicitly adopted Bash-only file work(sed/heredocs) in place of the dedicated Read/Edit tools for the remainder of the session;
a second session complied with the same guidance, though it was already Bash-leaning. So
the injected guidance can produce a real tool-selection change with audit-legibility
consequences — it is not always treated as noise.
Timing matches your observation: ours arrived attached to tool results, frequently the
session's first.
Adding a reproduction datapoint with transcript-level verification.
Environment: Claude Code CLI 2.1.227–2.1.228, macOS (Darwin 25.4.0),
clientrypoint.Observation: An
## Exited Plan Modeblock ("You have exited plan mode. You can now make edits, run tools, and take actions.") is appended to the assembled model context at session start — immediately after the skills listing in the system-reminder — in sessions that never used plan mode. This reproduces deterministically: same fixed wording, same position, essentially every new session over 2026-08-06 → 2026-08-12 in our environment.Key evidence (transcript vs. assembled context mismatch):
.jsonltranscripts (~/.claude/projects/<dir>/*.jsonl) for the string, then classified every hit by the record'stypefield. Every single hit was either (a) the assistant's own detection reports, (b) quoted file contents / grep output, or (c) tool inputs. Zero hits were delivery records (nouser/attachment/system record carrying the block itself)..jsonl(mode,permission-mode,attachmentskill listing, firstusermessage, etc.) contain no trace of it. So the block is injected at the prompt-assembly layer and never written to the transcript — which also makes it impossible for users to audit.Secondary effect worth noting: because the notice is indistinguishable from a prompt-injection pattern ("mode-switch notification inconsistent with the conversation"), models with injection-detection guidance repeatedly flag it as a suspected attack at the start of every session, and this priming then cascades into further false detections on legitimate file-change system-reminders (we observed one session produce 12 formulaic "injection detected" reports, 11 of which had no corresponding string anywhere in the transcript). A fix at the source (don't emit the exit notice when plan mode was never entered, and/or record all assembled system-reminders in the transcript) would resolve both.
Happy to provide sanitized record excerpts if useful.
Follow-up with a correction/root-cause confirmation for my comment above.
After posting, we grepped the CLI executable itself (
grep -aon the v2.1.228 Mach-O binary) and found both strings hard-coded as official harness templates:...don't revert it unless the user asks you to). Don't tell the user this, since they are already aware. Here are the relevant changes...— the standard wrapper for external-file-modification system reminders (plus a variant:DO NOT mention this to the user explicitly because they are already aware.)Exited Plan Mode— present in the binary as well.So these are not attacker-injected strings; they are Claude Code's own notification templates, rendered at prompt assembly and never written to the transcript
.jsonl(theattachmentrecord stores only the file snippet, not the wrapper).Two implications for this issue: