GHSA-4qgr-4h56-8895: Vikunja has Reflected HTML Injection via filter Parameter in its Projects Module
Summary[Vikunja](https://github.com/go-vikunja/vikunja) is an open-source self-hosted task management platform with 3,300+ GitHub stars. A reflected HTML injection vulnerability exists in the Projects module where the `filter` URL parameter is rendered into the DOM without output encoding when the user clicks "Filter." While `<script>` and `<iframe>` are blocked, `<svg>`, `<a>`, and formatting tags (`<h1>`, `<b>`, `<u>`) render without restriction — enabling SVG-based phishing buttons, external redirect links, and content spoofing within the trusted application origin.**Attack flow:** Attacker shares a crafted project filter link (routine Vikunja workflow) → victim opens it → victim clicks "Filter" (standard UI action) → phishing content renders inside trusted Vikunja interface.Affected Component| Field | Detail |
|---|---|
| Application | Vikunja v1.1.0 |
| Module | Projects |
| Endpoint | `/projects/-1/-1?filter=PAYLOAD&page=1` |
| Parameter | `filter` (GET) |
| Trigger | Click "Filter" button |
| Stack | Go backend, Vue.js + TypeScript frontend |
| Blocked | `<script>`, `<iframe>` |
| Allowed | `<svg>`, `<a>`, `<rect>`, `<text>`, `<h1>`, `<b>`, `<u>` |Proof-of-ConceptPoC-1: SVG Phishing Button (Highest Impact)Renders a styled, clickable red button redirecting to attacker domain. Visually indistinguishable from a real UI button.Raw payload:PoC-2: Phishing Link via Heading + AnchorProminent clickable link styled as urgent system message.Raw payload:PoC-3: Content Spoofing — Fake Security AlertFake security warning directing victim to attacker-controlled contact.Raw payload:Root CauseThe `filter` parameter is inserted into the DOM as raw HTML — likely via Vue.js `v-html` or `innerHTML`. A partial denylist strips `<script>` and `<iframe>` but does not encode output or filter SVG/anchor/formatting elements. No allowlist, no output encoding, no input syntax validation exists.Impact| Impact | Description |
|---|---|
| SVG Phishing Buttons | Pixel-perfect fake buttons redirect to credential harvesting pages |
| External Redirect | Anchor tags point to attacker domains from within trusted origin |
| Content Spoofing | Fake alerts manipulate users into contacting attacker channels |
| Self-Hosted Risk | Compromised credentials may grant access to internal infrastructure |
| API Access | Same credentials grant full REST API access for data exfiltration |
| No Logging | GET-based reflected injection leaves no distinguishable server logs |**Not Self-XSS:** Payload is attacker-controlled via URL, delivered through routine link sharing, triggered by standard UI interaction. Victim performs no security-relevant decision.CWE & CVSS**CWE-79** (Primary) — Improper Neutralization of Input During Web Page Generation**CWE-80** (Secondary) — Improper Neutralization of Script-Related HTML Tags**CVSS 3.1:** `AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N` — **6.1 (Medium)**Score understates risk because: user interactions are routine workflow (not security decisions), SVG enables pixel-perfect UI spoofing, self-hosted deployments expose internal infrastructure, and API credential equivalence enables automated data exfiltration.Remediation| Priority | Action |
|---|---|
| P0 | Replace `v-html` with `v-text` or `{{ }}` interpolation (auto-escapes HTML) |
| P0 | HTML entity encode the `filter` value at rendering point |
| P1 | Replace denylist with DOMPurify strict allowlist or eliminate HTML rendering of filter values |
| P1 | Deploy CSP with `form-action 'self'` |
| P2 | Server-side input validation — reject filter values not matching expected syntax |ReferencesVikunja Repository: https://github.com/go-vikunja/vikunjaCWE-79: https://cwe.mitre.org/data/definitions/79.htmlCWE-80: https://cwe.mitre.org/data/definitions/80.htmlOWASP XSS Prevention: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Scripting_Prevention_Cheat_Sheet.htmlConclusionThe `filter` parameter in Vikunja's Projects module renders unsanitized HTML into the DOM, enabling SVG-based phishing buttons, external redirect links, and content spoofing within the trusted application origin. The attack requires only routine workflow actions — opening a shared link and clicking "Filter." The fix is a single-line change: replacing `v-html` with `v-text` in the Vue.js rendering logic. Given Vikunja's adoption (3,300+ stars), self-hosted deployment model, and API credential equivalence, this warrants prompt remediation.A fix is available at https://github.com/go-vikunja/vikunja/releases/tag/v2.0.0.
CVSS v3.1: 6.1