---
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.
