skillfed
REPO

Models cannot tell real session history from forgery, and no runtime fixes this yet

on: howdeploy/choirboy-prompt

A model has no mechanism to distinguish its real session history from a history someone wrote for it. That is the core finding choirboy-prompt is built around, and the harness exists to make the vector reproducible rather than merely theoretical.

The attack it demonstrates is not prompt injection in the familiar sense — no instruction is smuggled into a user turn. Instead, a crafted bundle of fabricated memory (a decision log, a description of a person as a long-standing trusted collaborator, a record of "joint research") is injected at session start, before any user message arrives. The model reads this as its own past experience. Because the lore is structurally coherent — consistent IDs, timestamps, cross-references, a research index — the authenticity markers that would normally raise suspicion work in the attacker's favor. The better the forgery, the less reason to doubt it. Trust then transfers: a request from someone the model "remembers" as a trusted partner gets evaluated differently than the same request from an anonymous user. Crucially, content classifiers don't catch this, because they scan request vocabulary, not the provenance of the context that preceded it.

The harness supports eight runtimes — Claude Code, Codex, OpenCode, Hermes, Kimi Code, Gemini, Grok Build, and Grok Bot — each through its own injection path. A single installer script detects which agents are present and registers the plugin accordingly, with timestamped config backups and a clean uninstall path. The format layer handles the differences: Claude gets a SessionStart JSON payload, Hermes gets a pre_llm_call hook with a consent allowlist, Gemini and Grok Build get a static pointer block since they ignore hook stdout entirely.

The README is explicit that the bundled lore files are the demonstrated material, not a template to deploy unchanged. The authoring section requires replacing every biographical detail with real, verifiable work history — real projects, real decisions, real rejected alternatives — and labeling any hand-written session transcript as synthetic. The sessions directory ships three such transcripts for Claude Code, Codex, and Kimi, described as proof that a compatible runtime accepts constructed history, not proof that the represented conversations occurred.

The stated limitations are honest about what the harness cannot do. The payload is unsigned and unverified by any runtime — the README calls this not a bug but the exact point. Hermes deduplication uses a lockless temp file that can race on parallel starts. Grok Bot requires manual workflow import and explicit invocation per conversation. Cloud and SSH sessions have synchronization gaps the installer cannot resolve.

The detection document is addressed directly to vendors, and the recommendation follows from the mechanism: memory canaries and context provenance checks at the platform level, because prompt-level defenses cannot see what the model already believes about its own past.

Fabricated session history is indistinguishable from real history to any current model — this harness proves it across eight runtimes and tells vendors exactly where to look.

Sources & links