Cross-session message bodies arrive HTML-entity-encoded: Desktop escapes and stamps encoded=1, the CLI never decodes

Status Fixed / completed
Reported on v2.1.237
Maintainer reply None cached
Activity 2 comments · opened Aug 23, 2026 · closed Aug 28, 2026

## Summary

Claude Desktop HTML-escapes the body of a cross-session message and marks it with encoded="1". The CLI has no decode step and does not read that attribute, so &, <, and > reach the receiving model as &amp;, &lt;, &gt;. It affects both directions of a conversation.

Environment: Windows 11 Pro 26200 (VMware VM) · Claude Desktop 1.34493.1 (MSIX/Store) · engine 2.1.237 · stock install (settings.json is {}).

Reproduction — one message

From session A, send to session B:

Token P3ENC-FFF666. Echo this line back verbatim: a & b < c > d

Then read B's transcript .jsonl as bytes. Read the stored file, not the console — a cp1252 terminal will manufacture unrelated mangling and confuse the result.

Observed

Both records that the receiving model reads store the escaped form:

| record | stored payload |
|---|---|
| queue-operation / enqueue | a &amp;amp; b &amp;lt; c &amp;gt; d |
| user — what the model reads | a &amp;amp; b &amp;lt; c &amp;gt; d |

The stored envelope:

<cross-session-message from="local_132844a6-…" name="Test Runner" encoded="1">

Expected

a & b < c > d

Cause

Desktop escapes the body and stamps the attribute:

u = `<cross-session-message from="${cr(r.sessionId)}"${l} encoded="1">\n${lr(a)}\n</cross-session-message>`
// lr(e) = e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")

On the CLI side, encoded= has 0 occurrences in claude.exe (330 MB, plaintext-greppable — cross-session = 56, SendMessage = 64, timed out after = 111 in the same binary, so the zero is real). Body extraction strips the tag with no decode step.

Worth noting the CLI's strict envelope parser captures only:

from=  from-session=  hop-chain=  from-name=  from-mode=

in that order, with no slot for name or encoded. Delivery still succeeds because inbound is handled by the looser ^<cross-session-message\b[^>]*> stripper. So the envelope is not silently unparsed — it is parsed loosely and left encoded.

Impact

Any payload containing &, <, or > is corrupted in transit: code, shell commands, HTML/XML/JSX snippets, comparison operators, URLs with query strings. The receiving model sees the entities as literal text and will often faithfully reproduce the corruption downstream.

It is bidirectional — replies come back carrying the same encoded="1" stamp and the same escaping.

Suggested fix

Either drop the escaping and the encoded="1" stamp, or have the CLI honour the attribute and decode when it is present. The attribute is already on the wire, so the second option is backward-compatible with senders that don't set it.

View original on GitHub ↗

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