---
id: c815bb87-3bbd-44eb-9fb1-cb818ec10a8c
title: release artifact filenames inject HTML into release pages
state: closed
labels:
- kind:security
assignees: []
milestone: null
created: 2026-10-27T18:08:32.834116005Z
updated: 2026-10-27T18:20:51.747619077Z
---
## What

`artifact_href()` interpolates the artifact path without HTML escaping or URL encoding:

`src/releases.rs:329-330`:

```rust
fn artifact_href(version: &str, path: &str) -> String {
    format!("/releases/{}/{path}", esc(version))
}
```

`src/releases.rs:363-365` puts this directly into `href="..."`.

## Reproduced

Create an artifact file whose name is:

```
evil" onmouseover="alert(1).txt
```

Build. The release page contains:

```html
<a href="/releases/v1.0/evil" onmouseover="alert(1).txt">…</a>
```

A quote and arbitrary markup/event handlers are injected into the page. Filenames are repo-controlled (`collect_artifacts` accepts any name), so this is stored XSS on the release page.

Also unencoded `#`/`?` in paths break the download link.

## Impact

Stored XSS / broken artifact links from `.forge` data.

## Fix

- Percent-encode the path for the URL, then HTML-escape the entire href (reuse the path encoder added for #89, or expose it from `build`).
- Add tests with `"`, `<`, `#`, `?`, and spaces in artifact names.
