id: cd6f8d85-f82c-4512-a6b8-e0b6be1647da title: 'issues/pulls: generated HTML in title= corrupts every row' state: closed labels:
- ui assignees: [] milestone: null created: 2026-10-27T17:24:52.388211661Z updated: 2026-10-27T17:45:41.669704879Z
What
The issues and pulls indexes pass generated HTML into a title= attribute:
src/forge.rs:1146—title="{state}",title="{created}"src/forge.rs:1215— same for pulls
state is <span class="pill ...">closed</span> and created is <time ...>1h ago</time>, so the inner quotes terminate the attribute. Every row renders literal closed"> / 1h ago">1h ago, and mobile cards show the same noise. The malformed markup also includes attributes that were meant for inner elements on the <td>.
This is not XSS today (the inner text is escaped, state classes are fixed), but it is fragile: any future user-controlled content in those titles becomes an injection point.
Reproduced
/issues/index.html and /pulls/index.html:
<td ... title="<span class="pill state-closed">closed</span>"><span ...
Visible: closed"> [closed] and 1h ago">1h ago.
Fix
Keep plain-text and HTML variants per cell: escaped plain issue.state / relative age in title=, HTML pill/time in the body. Add a test that the index contains no title="< and no "> artifacts.