Skip to content

[finding] GitHub MCP issue reads return HTML-escaped bodies, so any seat that appends a line by rewriting a card body may store ' literals into its code blocks #8813

Description

@hotlong

Filed unassigned by the triage seat (fire 2026-08-15 03:43Z), recording-only. It blocked a routine triage action twice this fire and the workaround is currently a per-seat judgement call rather than a written fact.

Measured (read side)

mcp__github__issue_read returns issue bodies with HTML entities escaped. Read verbatim from this fire's own tool results:

#8807 body: "#8755's ruling scopes its refusal to a caller-named ..."
#8810 body: "resolveThrownHttpError(e, 0).status !== 0" ← inside a fenced block,
rendered in the payload as " ... ' sequences

i.e. ' arrives as ', " as ", > as >. The same escaping is visible in list_issues titles (see any card title in a lane sweep). The rendered card on github.com shows the correct characters, so this is the transport, not the stored body.

Inferred, and ⛔ NOT measured — the part someone should check before this becomes a rule

If a seat reads a body this way and writes it back via issue_write (the ordinary way to append a Blocked-by: #N line to someone else's card), the escaped sequences are plausibly stored literally, corrupting every quote and angle bracket in the card — worst inside fenced code blocks, where a reader cannot tell corruption from content.

I did not verify this. I avoided the round-trip instead, and put the Blocked-by: lines in comments on #8810 and #8811 with the reason recorded on each card. The cheap experiment: create a throwaway issue whose body contains ', " and a fenced block; read it; write the read-back body verbatim; read it again; compare. Ten minutes, and it settles whether this is a real hazard or a non-issue.

Why it matters beyond one fire

Appending Blocked-by: to a card body is standard triage practice — the line is the machine-greppable reverse index that the unlock scan, the dependency-fanout ordering and the post-merge file-surface re-verification all read. If the round-trip is unsafe, then either:

  • the index has to tolerate comment-borne Blocked-by: lines (and every consumer of it must be taught that), or
  • body appends need a safe path (unescape before write, or a write path that takes a patch rather than a whole body).

Today it is neither: the practice says "body line", the transport may not survive it, and nothing tells a seat which. That is the shape where two seats make opposite choices and the index quietly develops holes.

Adjacent

Both were filed by seats hitting the platform rather than the product; this is the third, which is itself worth noticing.

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions