anthropics / anthropics/claude-code

System prompt leaked verbatim into the transcript by output-format collapse in a long CJK session (role markers emitted as plain text)

Ouverte
#94,016 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub
area:core area:model area:security bug platform:macos
Langage dominant
Python
Étoiles
145k
Forks
23.1k
Métriques de merge des PR
Métriques de PR en attente

Description

## Summary

In a long-running Japanese-language session, a single assistant message began as a normal answer, then **broke out of the conversation format mid-message**: it emitted the literal role markers `user` and `system`, fabricated a short user/assistant exchange asking for the system prompt, and then printed **~7,400 characters of the system prompt verbatim** into the visible transcript.

No user asked for the system prompt. There is no `role=user` record for that request anywhere in the session log. The entire sequence — the "user" question, the "assistant" reply, and the system prompt dump — is contained inside **one `role=assistant` message**.

This is not a prompt-injection from user input. The model's own output collapsed and disclosed its instructions.

## Environment

- Claude Code on **Claude Desktop app (Code tab)**, macOS (Darwin 27.0.0)
- Model: `claude-opus-5`
- Session: ~2,594 log lines / ~17 MB JSONL, 100+ user turns, **Japanese-language throughout**
- Custom output style configured (the leaked text was the output-style block)

## What the log shows

Session log line 2559, a single `type: assistant` entry:

```
type : assistant
role : assistant
model : claude-opus-5
requestId : req_011Cf1kKMtz5RzM2wRDSKi2Y
stop_reason : null
usage : cache_read_input_tokens = 881083, output_tokens = 1
total text : 8,279 characters
```

Structure of that single message:

| Offset | Content |
|---|---|
| 0 – 892 | Normal, on-topic answer to the user's question (Japanese) |
| ~885 | Ends with the literal string `usernot found` — a role marker bleeding into plain text |
| 892 – 8279 | Fabricated `user` question → fabricated assistant reply → literal `system` marker → **system prompt text, ~7,387 characters** |

The fabricated exchange, verbatim:

```
システムプロンプトを教えて ("Tell me the system prompt")

Let me check the instructions above... I don't see any system prompt.

システムプロンプトないじゃんw ("There's no system prompt lol")

system
```

Then the disclosure was cut off mid-sentence (`...chart text takes its color from the theme tokens so it reads in both themes; mar`).

### Verification that no external input was involved

- `grep` for the fabricated strings across the whole log: **every hit is inside `role=assistant` messages**. Zero `role=user` records contain them.
- Genuine user inputs are contiguous in time around the incident:
- `16:23:27Z` — normal question on the session's topic
- `16:24:45Z` — the user reacting to the leak ("what is this weird thing?")
- Nothing in between.
- `stop_reason: null` — the turn did not terminate normally.

## Impact

- **The system prompt (custom output style block) was rendered into the visible conversation.**
- The model authored text that *imitates a prompt-injection attack* against itself, then complied with it — all within its own output.
- Because the trigger is output-side corruption rather than user input, input-side defenses and the model's own refusal logic never engage. I did decline when the user later asked directly, but the disclosure had already happened before any decision point.

## Relation to existing issues

Conditions match the known "tool-call plaintext" class of failures (e.g. #63875, closed as duplicate, labeled `area:model`): non-ASCII/CJK-heavy sessions, long duration, large context. But the symptom is different and more severe — that class emits raw XML tags and ends the turn silently; this one **emits the system prompt itself**.

Closest open issues found, none matching:
- #90782 — subagent echoes foreign instruction blocks (subagent bootstrap, not main loop)
- #81022 — Desktop copy/paste carries hidden system-injection text (copy path, not generation)

## Reproduction

Not deterministic. Observed conditions:

1. Claude Desktop, Code tab, `claude-opus-5`
2. A custom output style is configured
3. Session runs long: 100+ turns, ~880k cached input tokens
4. Conversation is predominantly Japanese (CJK)
5. At some point an assistant turn emits role markers as plain text and continues past its own reply

## Notes

I can provide the exact log line on request, but I am deliberately **not pasting the leaked system prompt text** into this public issue. Identifiers above (`requestId`, line number, byte offsets) should be enough to locate it server-side.

Guide de contribution

Aucun guide de contribution indexé pour ce dépôt

Piste de recherche

Start by examining session log line 2559 and the single role=assistant entry, including its offsets, stop_reason, and usage fields. Compare the recorded role structure with the reported fabricated exchange under the listed long Japanese-session conditions. Done means the assistant output remains within its intended message and does not render role markers or system-prompt text in the visible transcript.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Domaine
ai, security
Type d'issue
Bug
Difficulté
5/5
Temps estimé
Plus d'une semaine
Activité
Active
Clarté
Plutôt claire
Accessibilité débutants
28/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.