Xen Orchestra Auth Bypass Exploited for Host Takeover (VSA-2026-062)
An empty JSON cookie object bypasses Xen Orchestra authentication and yields admin access; attackers are exploiting it, and 6.9.2 fixes it.
TL;DR
- An empty JSON object in the
authenticationTokencookie makes Xen Orchestra treat the request as an authenticated administrator. The token lookup receives the object, treats it as an unfiltered query, and returns the first stored token. - Xen Orchestra before 6.9.2 on the stable channel and before 6.10.1 on the latest channel is affected, including the Xen Orchestra Appliance. The
xo-serverpackages are 5.211.2 and 5.213.1. - The vendor rates the flaw Critical and says it is actively exploited. No CVE is assigned, and the flaw is not in CISA's Known Exploited Vulnerabilities catalog as of November 11, 2026.
- Update to 6.9.2 or 6.10.1, or to
xo-server5.211.2 or 5.213.1. If you cannot update, block the empty-token cookie at the proxy and remove the instance from the internet.
Am I affected?
All of these must hold:
- You run Xen Orchestra before 6.9.2 on the stable channel or before 6.10.1 on the latest channel. The Xen Orchestra Appliance is affected too.
- The REST API is reachable by the attacker. The vulnerable path is the REST authentication middleware, which reads the
authenticationTokencookie. - The instance has at least one unexpired authentication token in its token collection. A token is created whenever a user signs in and chooses to stay signed in, so most active deployments have one.
The vendor says the flaw is in Xen Orchestra itself, not in XCP-ng. The impact reaches the managed pools because Xen Orchestra holds their administrator credentials. A compromised console can run commands on every host it manages.
Xen Orchestra is the management console for XCP-ng, the open-source XenServer alternative. The project repository has 998 stars on GitHub, and the community container image ronivay/xen-orchestra has 2,777,836 pulls on Docker Hub, a signal of how many deployments run the console.
| Channel | Affected versions | Fixed versions |
|---|---|---|
| Stable | Xen Orchestra before 6.9.2, xo-server before 5.211.2 |
Xen Orchestra 6.9.2, xo-server 5.211.2 |
| Latest | Xen Orchestra before 6.10.1, xo-server before 5.213.1 |
Xen Orchestra 6.10.1, xo-server 5.213.1 |
Check the xo-server package version. On a source install, run this from the repository root:
node -p "require('./packages/xo-server/package.json').version"
npm ls xo-server -g --depth=0
On the Xen Orchestra Appliance, open the About page in the web interface and read the Xen Orchestra version. The vendor also publishes the fixed xo-server versions in the advisory. If the version is 5.211.2 or 5.213.1, the instance has the fix; the earlier numbers are affected.
How do I fix it?
Update Xen Orchestra to 6.9.2 on the stable channel or 6.10.1 on the latest channel, then restart the service. Source installations should update to the latest master and rebuild.
- On the stable channel, update to Xen Orchestra 6.9.2, which ships
xo-server5.211.2. - On the latest channel, update to Xen Orchestra 6.10.1, which ships
xo-server5.213.1. - On a source installation, pull the latest
master, run the usual install and build steps, and restartxo-server. - Confirm the new
xo-serverversion with the command in "Am I affected?". - If you use the appliance, apply the vendor update and confirm the About page shows 6.9.2 or 6.10.1.
If you cannot update, remove the instance from the internet and block the empty token at the proxy. The vendor lists three mitigations:
- Put Xen Orchestra on a dedicated management network and do not expose it to the internet.
- Block the IP addresses and the Tor domain the vendor associates with the campaign. The list is in "How do I check if I was compromised?".
- Add a WAF or reverse-proxy rule that rejects
authenticationToken=j:{}andauthenticationToken=j:%7B%7D. The vendor warns that regex rules can be bypassed with other encodings, so treat this as a stopgap.
Rotate every credential the console can reach if you find any sign of compromise. That includes the pool secret, host root passwords, user accounts, OTP secrets, backup remote credentials and mail server passwords. The vendor recommends a full reinstall after a confirmed compromise because cleanup alone cannot guarantee that a backdoor is gone.
What is the root cause?
The REST API parses cookies with the cookie-parser middleware, which understands a j: prefix as JSON. A cookie value of authenticationToken=j:%7B%7D is decoded to the empty object {}. The REST middleware then passes that object to the authentication provider as the token:
async #authenticateUser(req) {
const { cookies, ip } = req
const token = cookies.authenticationToken ?? cookies.token
if (!token) {
throw invalidCredentials()
}
const { user } = await this.#app.authenticateUser({ token }, { ip })
The provider only checks whether the value is truthy. An empty object is truthy, so the request continues:
this.registerAuthenticationProvider(async ({ token: tokenId }, { ip } = {}) => {
if (!tokenId) {
return
}
try {
const token = await app.getAuthenticationToken(tokenId)
getAuthenticationToken expects a string or an object with an id field. It reads properties.id without checking the type, so the empty object produces undefined:
async getAuthenticationToken(properties) {
const id = typeof properties === 'string' ? properties : properties.id
const token = await this._getAuthenticationToken(id, properties)
_getAuthenticationToken then passes the original object to the token collection when it is present:
async _getAuthenticationToken(id, properties) {
const token = await this._tokens.first(properties ?? id)
The collection's first({}) treats an empty object as a query with no conditions and returns the first token it holds. If that token has not expired, the provider authenticates the request as the token's owner. The attacker does not need to know any credential; the object itself selects the record.
How is it exploited?
- The attacker sends an HTTP request to the Xen Orchestra REST API with the cookie
authenticationToken=j:%7B%7D(orauthenticationToken=j:{}). cookie-parserdecodes thej:value into the empty object{}.- The REST middleware passes
{ token: {} }to the authentication provider. The provider's truthiness check accepts the object. getAuthenticationTokenreadsproperties.id, which isundefined, and forwards the original object to the token collection.- The collection's
first({})returns the first token. The provider checks its expiry and authenticates the request as that token's owner. - The attacker calls
/rest/v0/users/me/authentication_tokenswith the resulting session and receives reusable login token IDs. - The attacker uses an administrator session to change configuration, run commands on managed pools and reach the XCP-ng hosts as root.
The vendor says the exploit can lead to arbitrary code execution on managed pools and a full XCP-ng node takeover. It does not publish the exact request sequence beyond the cookie pattern, and the indicators below are the campaign's, not a complete detection method.
How does the attack flow?
One empty JSON object replaces the token identifier, the token collection returns its first record, and the request becomes an administrator session that reaches the managed hosts.
no string check"] D --> E["token collection first({})
returns first token"] E --> F["session as token owner
usually an administrator"] F --> G["commands on managed pools
and XCP-ng hosts"]
What can an attacker do?
An attacker who reaches the REST API can authenticate as the owner of the first unexpired token. In practice that is an administrator, because the session can then call the administrator-only REST routes.
The impact includes:
- Reading and changing Xen Orchestra configuration, users and authentication tokens.
- Running commands on the managed pools through Xen Orchestra's host access.
- Taking over an XCP-ng node as root, as the vendor describes.
- Harvesting configuration and credentials for proxies, backup remotes (NFS, S3, Azure, SMB), the root account, the pool secret, user accounts, OTP secrets and mail server settings.
The conditions are the same as in "Am I affected?": an affected Xen Orchestra version, the REST API reachable by the attacker, and at least one unexpired token in the collection. The vendor says the vulnerability is actively exploited, so an internet-facing instance should be treated as exposed even before you find a token.
Why does the fix work?
The fix validates the token identifier before it reaches the collection and builds the query from the validated fields only. It adds a string check and changes the lookup:
+const isNonEmptyString = value => typeof value === 'string' && value.length !== 0
+
export default class {
@@
this.registerAuthenticationProvider(async ({ token: tokenId }, { ip } = {}) => {
- if (!tokenId) {
+ if (!isNonEmptyString(tokenId)) {
return
}
@@
- async _getAuthenticationToken(id, properties) {
- const token = await this._tokens.first(properties ?? id)
+ async _getAuthenticationToken(id, userId) {
+ if (!isNonEmptyString(id) || (userId !== undefined && !isNonEmptyString(userId))) {
+ return
+ }
+
+ // build the query from validated fields only, never forward caller-supplied objects
+ const token = await this._tokens.first(userId === undefined ? id : { id, user_id: userId })
getAuthenticationToken now destructures only id and user_id from the input and passes those values to the private lookup. A cookie that decodes to {} fails the string check before any database query runs. A valid string token still works, and a compound { id, user_id } lookup is preserved. Extra keys an attacker adds to the object are ignored.
The fix is complete for the described path. The vendor's advisory says the REST API, the sign-in route and the JSON-RPC session.signIn method now reject non-string and empty token IDs. It does not cover third-party code that calls the token provider with its own object, so keep the instance off the public internet.
How do I check if I was compromised?
The vendor says there is no log entry for a successful unauthenticated access, so packet capture is the most direct check. Capture traffic on the Xen Orchestra host or its reverse proxy and search for the cookie pattern, including the encoded form:
tcpdump -i any -A -s 0 'tcp port 80 or tcp port 443' | grep -iE 'authenticationToken=j:(%7B%7D|\{\})'
grep -iE 'authenticationToken=j:(%7B%7D|\{\})' /var/log/nginx/access.log
The same request appears in the vendor's indicators as authenticationToken=j:%7B%7D or authenticationToken=j:{}. A hit is a lead: legitimate clients should not send an empty object as a token.
Check the XCP-ng hosts for the campaign's artifacts:
xe vm-list params=name-label,platform | grep -B1 'hvm_serial: file'
zgrep -- '-serial file:' /var/log/xensource.log*
ls -la /etc/ld.so.preload /.ustar* /etc/cron.d/zz-ustar*
The vendor's indicators include a virtual machine named pivot2, VMs configured with the hvm_serial: file parameter, and the files /etc/cron.d/zz-ustar2, /etc/cron.d/zz-ustar, /.ustar5 and /.ustar6. It also lists the IP addresses 91.211.251.112, 193.148.56.72, 37.221.208.216, 45.66.35.11, 64.65.0.120, 64.65.62.160, 89.47.51.90 and 92.60.37.247, plus the Tor domain ustar3rqxgnskzgnwkgpofgtvxevm6cx3lxdbwt4mndtveqyaohid.onion.
If you find any of these, rotate every credential the console can reach and rebuild the instance. The vendor says cleanup alone cannot guarantee that all backdoors are removed.
Timeline
- 2026-11-10 08:29 UTC: the fix commit
50166fe3is merged as pull request #10748. - 2026-11-10: Vates publishes VSA-2026-062 and the fixed Xen Orchestra 6.9.2 and 6.10.1 releases.
- 2026-11-10: the vendor reports active exploitation from the listed IP address and Tor domain.
FAQ
Is there a CVE?
No CVE is assigned as of November 11, 2026. The vendor tracks the issue as VSA-2026-062, and the advisory is the authoritative record. The absence of a CVE does not mean the flaw is less urgent: the vendor says it is actively exploited.
Does this affect XCP-ng hosts directly?
The flaw is in Xen Orchestra, not in the XCP-ng host software. The hosts are at risk because Xen Orchestra manages them with privileged credentials. An attacker who takes over the console can use that access to run commands on the hosts, which is why the vendor describes a full node takeover.
Which version should I install?
Install Xen Orchestra 6.9.2 on the stable channel or 6.10.1 on the latest channel. On a source installation, update to the latest master and confirm that xo-server is 5.211.2 or 5.213.1. The appliance update carries the same fix.
Can I block the cookie at the proxy instead?
A rule that rejects authenticationToken=j:{} and authenticationToken=j:%7B%7D blocks the campaign's request, but the vendor warns that other encodings can bypass a narrow regex. Use the rule only until you update, and keep the instance off the public internet.
Was this exploited as a zero-day?
The vendor says the flaw is actively exploited but does not say when the activity started or whether the attacks began before the fix. It also does not say whether the vulnerability was used as a zero-day. Treat the exposure window as unknown and check the hosts for the listed artifacts.
What should I rotate after a compromise?
Rotate every credential the appliance can reach: the pool secret, host root passwords, Xen Orchestra user accounts, OTP secrets, proxy configuration, backup remote credentials for NFS, S3, Azure and SMB, and the mail server password. Rebuild the appliance from a known-good image after rotating.
Find exposed Xen Orchestra consoles with Ostorlab
Ostorlab's attack surface discovery inventories the internet-facing hosts in your estate, so you can see which Xen Orchestra consoles and management interfaces answer from outside your network before you patch them. Use the inventory to find the consoles that should be on a management network and to prioritize the ones that are still exposed.
References
- Vates advisory VSA-2026-062: https://docs.vates.tech/security-advisories/advisories/2026/vates-sa-2026-062/ (checked November 11, 2026)
- Fix pull request #10748: https://github.com/vatesfr/xen-orchestra/pull/10748 (checked November 11, 2026)
- Fix commit 50166fe3: https://github.com/vatesfr/xen-orchestra/commit/50166fe3a49c02069d35ba9046ca4a1f77f4e11d (checked November 11, 2026)
- Vulnerable
authentication.mjsat the parent commit: https://github.com/vatesfr/xen-orchestra/blob/724402733b2381d93372db0183e21df9d2c457f7/packages/xo-server/src/xo-mixins/authentication.mjs (checked November 11, 2026) - Vulnerable
rest-api.mjsat the parent commit: https://github.com/vatesfr/xen-orchestra/blob/724402733b2381d93372db0183e21df9d2c457f7/packages/xo-server/src/xo-mixins/rest-api.mjs (checked November 11, 2026) - Xen Orchestra repository: https://github.com/vatesfr/xen-orchestra (checked November 11, 2026)
- Community Xen Orchestra container image: https://hub.docker.com/r/ronivay/xen-orchestra (checked November 11, 2026)