# Arcane Backend: Unauthenticated reflected XSS via SVG color parameter enables admin account takeover

Unauthenticated color param on Arcane's /api/app-images/logo is reflected unescaped into an SVG <style> block, letting script run same-origin and ride an admin's JWT cookie.

- Payout: Research
- Severity: high
- Program: Arcane
- Found by: offset
- Disclosed: 2026-05-18
- CVE: CVE-2026-45627
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-q2pj-8v84-9mh5
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-q2pj-8v84-9mh5
- Tags: area:web domain:web impact:ato impact:internal-access impact:privesc kind:research platform:ghsa sev:high tech:go technique:source-review vuln:xss

**Target:** GET /api/app-images/logo SVG rendering endpoint
**Root cause:** The `color` query parameter is substituted into the embedded logo.svg via strings.ReplaceAll with no escaping, landing inside a `<style>` element so a crafted value closes the style block and injects a `<script>`.
**Steps:**
1. Note the route is registered with an empty `Security: []map[string][]string{}`, so auth middleware short-circuits and no JWT check runs.
2. Confirm `GetLogoInput.Color` has no validation tags and flows to `applyAccentColorToSVG`, which does `strings.ReplaceAll(svgStr, "fill:#6d28d9", fmt.Sprintf("fill:%s", accentColor))`.
3. The bundled logo.svg contains `<style id="style1" type="text/css">.st0{fill:#6d28d9}</style>`.
4. Send `GET /api/app-images/logo?color=red}</style><script>fetch('/api/users',...)</script><style>x{` to close the style block and inject a script element.
5. Response is served as `image/svg+xml` with no CSP or `X-Content-Type-Options`; navigate a logged-in admin to the URL (or iframe/window.open) to execute script in Arcane's origin.
6. Script runs same-origin, so the HttpOnly JWT cookie is auto-attached to `fetch()` calls; call `POST /api/users` to create an attacker-controlled admin.
**How found:** Code review of the Huma route registration spotted the explicitly empty `Security` requirement marking the endpoint public, then tracing the unvalidated `color` query param into `strings.ReplaceAll` against the bundled SVG's `<style>` block revealed the injection point; a grep confirmed no CSP or nosniff headers.
**Exploitation:** Attacker crafts a URL to the unauthenticated logo endpoint with a `color` value that breaks out of the `<style>` block and injects `<script>`. Victim (an authenticated admin) visits the link or loads it in an iframe; the SVG executes in Arcane's origin, and same-origin fetch calls carry the HttpOnly JWT cookie. The script invokes privileged APIs such as `POST /api/users` to create a persistent admin account, then uses that to manage Docker containers, registries, GitOps secrets and SSH/registry credentials.
**Escalation:** XSS in a low-privilege image endpoint escalates to full admin account takeover by session-riding the HttpOnly JWT cookie and creating a new admin via `POST /api/users`, yielding standalone persistent access to Docker hosts and stored secrets.
**Insight:** When an SVG template is mutated by string replacement, check whether the placeholder sits inside a `<style>` or attribute context — closing the block with `}` or a quote yields script execution. Also audit Huma `Security: []` registrations: an empty slice explicitly disables auth middleware, making such routes unauthenticated even on otherwise protected APIs.

## Proof of concept (copied exactly from the original report)

**Crafted color parameter SVG XSS payload**

```
so a `color` value like `red}</style><script>fetch('/api/users',...)</script><style>x{` produces a valid SVG that closes the `<style>` element and embeds a `<script>` element.
```

