Jan 23, 2026·6 min read·18 visits
XWiki Platform trusted user input a little too much in its `logging_macros.vm` template. By supplying a malicious extension ID during an installation request, an attacker can poison the logs. When an admin views these logs to debug the failure, the script executes, potentially leading to session hijacking. Fixed in versions 16.10.12, 17.4.5, and 17.8.0-rc-1.
A reflected Cross-Site Scripting (XSS) vulnerability in the XWiki Platform's logging infrastructure allows attackers to inject malicious scripts via crafted extension identifiers, targeting administrators viewing system logs.
XWiki is a beast. It's a second-generation wiki engine written in Java, but its frontend logic relies heavily on Velocity templates. For those uninitiated in the ancient arts of Java templating, Velocity is powerful. It lets you mix logic with HTML generation seamlessly. But as with all powerful tools, it assumes you know what you are doing. If you hand it raw data, it prints raw data.
In the grand tapestry of a complex application, logging is usually the boring part. It's the janitor of the codebase—quietly cleaning up errors and storing them for later. Nobody expects the janitor to stab them in the back.
However, in XWiki, logs aren't just text files in /var/log. They are rich, interactive elements presented in the UI. When you try to install an extension, the system logs the progress. If it fails, it logs the error. And if the error contains user input that hasn't been scrubbed, the UI doesn't just display the error—it runs it. CVE-2026-24128 is exactly that: a case where the system tried to be helpful by hyperlinking an extension ID, only to accidentally turn a typo into a tactical nuke.
The vulnerability lives in xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-templates/src/main/resources/templates/logging_macros.vm. This template is responsible for making log messages look pretty in the browser. Specifically, it handles messages related to the Extension Manager—the part of XWiki that installs plugins and themes.
The logic seems innocent enough: if a log message involves an extension ID, turn that ID into a clickable link so the user can easily visit the extension's homepage. The developers assumed that an Extension ID would be a safe string—maybe something like org.xwiki.platform:xwiki-platform-web.
But assumptions are the mother of all security advisories. The code didn't check if the ID was actually an ID. It simply took the $argument variable (holding the ID) and shoved it directly into the anchor tag's text content. It's the classic "Reflected XSS via Error Message" pattern. You ask the server for something that doesn't exist, and the server helpful echoes back: "I couldn't find [YOUR_MALICIOUS_PAYLOAD] for you."
Because Velocity in this context does not auto-escape variables placed inside string literals or assignments unless explicitly told to, the browser receives the raw payload. If that payload is <script>alert(1)</script>, the browser obeys.
Let's look at the crime scene. The vulnerable code was inside a macro used to format log arguments. Here is the simplified logic before the fix:
#if ($argument.id) #set ($version = $argument.versionConstraint)
#set ($_extensionURL = "#getExtensionURL($argument.id, $version)")
#set ($_extensionName = $argument) #end
#set ($message = "$message<a href=""$_extensionURL"" class=""extension-link"">$_extensionName</a>")
The variable `$_extensionName` is assigned the raw `$argument` object (which toString()s to the attacker's input). It is then placed between the `<a>` tags.
The fix is elegantly simple. XWiki developers introduced the standard XML escape tool. This converts `<` to `<` and `>` to `>`, neutering any HTML tags.
```diff
- #set ($_extensionName = $argument)
+ #set ($_extensionName = $!escapetool.xml($argument))
By wrapping the argument in $!escapetool.xml(), the browser renders the malicious string as harmless text rather than executing it. It's a one-line change that closes a massive window of opportunity.
So, how do we weaponize this? We need to trigger a log event that contains our payload. The Distribution Wizard or the Extension Manager are perfect candidates. These components take an Extension ID as input to look up packages.
Here is the attack chain:
org.xwiki:fake<img src=x onerror=alert(document.cookie)>logging_macros.vm to render the error.This is a "stored-reflected" scenario: the payload is reflected from the immediate request log, or transiently stored in the job status log, waiting for the victim to look at it.
Why is this critical? It's just XSS, right? In the context of a Wiki, XSS is often game over. XWiki isn't just a blog; it's an enterprise knowledge management system. It often holds proprietary data, internal documentation, and sometimes credentials.
If an attacker can execute JavaScript in the context of an XWiki administrator:
JSESSIONID or other authentication tokens.This isn't just popping an alert box; it's handing over the keys to the castle.
If you are running XWiki, stop reading and start patching. The vulnerability is fixed in XWiki Platform versions 16.10.12, 17.4.5, and 17.8.0-rc-1.
If you cannot upgrade immediately, you have very few good options. You could attempt to manually patch the logging_macros.vm file if you have filesystem access to the server, but modifying core templates is risky and gets overwritten during updates.
Defensive In-Depth:
script-src 'self'). This kills the majority of XSS vectors, although it requires careful tuning for a dynamic platform like XWiki.%3Cscript or %3Cimg sent to /bin/view/XWiki/DistributionWizard.CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
XWiki Platform XWiki | >= 7.0-milestone-2, < 16.10.12 | 16.10.12 |
XWiki Platform XWiki | >= 17.0, < 17.4.5 | 17.4.5 |
XWiki Platform XWiki | >= 17.5, < 17.8.0-rc-1 | 17.8.0-rc-1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| Attack Vector | Network |
| CVSS Score | Critical (Vendor Internal) |
| Impact | Session Hijacking / Potential RCE |
| Exploit Status | PoC Available (Theoretical) |
| KEV Status | Not Listed |
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.