# Xen Orchestra / XOA authentication bypass: Vates VSA-2026-062 ("Empty-object login token")

CybaVerse detection pack for UK MSPs running Microsoft Sentinel and Microsoft Defender across client estates.
Built 10 Nov 2026. Sources fetched 10 Nov 2026 between 17:04 and 17:07 GMT (Europe/London, same as UTC today).

**The KQL in this pack has NOT been run against a live tenant.** It has been parsed offline with Kusto.Language against
an assumed schema subset (`tests/kql_parse.ps1`). Test it in your own workspace before you rely on it.

## Summary

| Item | Detail |
|---|---|
| Advisory | Vates VSA-2026-062, "Empty-object login token", published and updated 10 Nov 2026: https://docs.vates.tech/security-advisories/advisories/2026/vates-sa-2026-062/ |
| CVE | None assigned (Vates advisory index lists no CVE; NVD keyword searches on 10 Nov 2026 found none) |
| CVSS | None. The Vates advisory shows CVSS 4.0 as "Not available yet" |
| Vendor rating | Vates rates it Critical on its own severity scale ("We classify the impact as Critical"). This is the vendor's label, not a CVSS score, and this pack adds no severity label of its own |
| Exploited | Yes, per Vates: "This vulnerability is actively exploited by a threat actor operating from 91.211.251.112:8001 and ustar3rqxgnskzgnwkgpofgtvxevm6cx3lxdbwt4mndtveqyaohid.onion:3333 (via Tor)" |
| CISA KEV | Not listed (catalog version 2026.11.09, released 9 Nov 2026 19:54 GMT; no entry for Xen Orchestra, XOA, XCP-ng or Vates). With no CVE, KEV cannot list it yet. Patch now regardless |
| Affected | Xen Orchestra (sources installs) and the Xen Orchestra Appliance (XOA). The flaw is in xo-server, the XO back end, not in the XCP-ng hypervisor. XCP-ng hosts are the downstream target |
| Impact (Vates) | "An adversary can bypass authentication and perform actions with 'Admin' privilege. Xen Orchestra compromise can lead to arbitrary code execution on managed pools and a full XCP-ng node takeover as root." |
| Fixed | xo-server 5.213.1 (latest channel, in Xen Orchestra 6.10.0 as updated on 10 Nov) and xo-server 5.211.2 (stable channel, in Xen Orchestra 6.9.1 as updated on 10 Nov) |
| Credit | Found by security researchers (credited in the Vates advisory) |

## How the bug works (Vates wording, summarised)

Vates: "REST cookie parsing turns `authenticationToken=j:%7B%7D` into `{}`. REST authentication passes that object to the
XO token provider without requiring a string. The token collection treats `{}` as an unfiltered lookup and returns its
first token; the provider authenticates as that token's owner if it is unexpired. The authenticated
`/rest/v0/users/me/authentication_tokens` route then returns reusable login token IDs."

So no password is needed. The attacker needs network reach to the XO web interface, and XO must hold at least one
unexpired authentication token (our reading of the Vates summary: the bypass borrows an existing token). The fix
(Vates fix, merged 10 Nov 2026 08:29 GMT) rejects non-string and empty token IDs on the REST API, `/signin` and the
JSON-RPC `session.signIn` method.

We do not reproduce the request. The cookie strings below appear only as log hunting patterns, as Vates publishes them.

## Versions: read this before you trust a version number

| What you see | Verdict | Why |
|---|---|---|
| xo-server 5.213.1 or later 5.213.x | PATCHED | Vates names 5.213.1 (latest channel) |
| xo-server 5.211.2 or later 5.211.x | PATCHED | Vates names 5.211.2 (stable channel) |
| xo-server 5.213.0 on XOA | VULNERABLE | The build XO 6.10.0 first shipped with on 29 Oct 2026 (vendor CHANGELOG) |
| xo-server 5.213.0 from sources | NEEDS MORE INFO | `packages/xo-server/package.json` on master still reads 5.213.0 after the fix merged. Check your git history contains commit `50166fe3` and that you rebuilt |
| xo-server 5.212.x | VULNERABLE | Technical release of 23 Oct 2026, before the fix, below 5.213.1 |
| xo-server below 5.211.2 | VULNERABLE | Before both fixed builds |
| xo-server 5.214 or later, or 6.x | NEEDS MORE INFO | Not a build Vates named. Confirm against the advisory |
| XO 6.9.1 or 6.10.0 label only | NEEDS MORE INFO | Vates says these versions "has been updated" to include the fix. Both labels existed before 10 Nov with vulnerable xo-server (5.211.1 and 5.213.0 per the vendor CHANGELOG). The XO label alone does not prove the fix |
| XO before 6.9.1 (including every XO 5.x) | VULNERABLE | Vates: affected "in Xen Orchestra before 6.9.1 (stable) and 6.10.0 (latest)" |

Vendor text inconsistency: the Affected Versions line reads "xo-server before 5.213.1 and 5.213.2", while the
Resolution list names 5.213.1 (latest) and 5.211.2 (stable). We follow the Resolution list and treat "5.213.2" as a typo
for 5.211.2. This is our interpretation and is marked UNVERIFIED until Vates corrects or confirms it.

Where to read the version: the XO About page (`https://your-xo/v5/#/about`) shows xo-server and xo-web versions; XOA
updates through XOA > Updates or `xoa-updater` (vendor docs). Sources installs should compare their commit to `master`.

## Vendor advice (Vates, VSA-2026-062)

1. Update as soon as possible. Fixes are on the `latest` and `stable` channels.
2. Do not expose Xen Orchestra to the Internet. Put it on a dedicated management network.
3. Block ingress and egress traffic to `91.211.251.112`, and block Tor to prevent communication with the onion host.
4. Block the empty token in a WAF or reverse proxy (`authenticationToken=j:{}` and `authenticationToken=j:%7B%7D`).
   Vates: "be cautious with regex, the rule can be bypassed using other formats".
5. If XO has been compromised, rotate all passwords and secrets used by Vates VMS "like proxy, backup, S3, root account,
   users account, etc.". Vates: "Configuration exfiltration and credential harvesting cannot be ruled out."
6. Detection (Vates): "In the case of a successful exploitation, there is no log to detect unauthenticated access."
   Monitor HTTP requests (tcpdump or Wireshark) for the two patterns, look for a `pivot2` VM, VMs with
   `hvm_serial: file`, `-serial file:` in `/var/log/xensource.log*`, and the files `/etc/cron.d/zz-ustar`,
   `/etc/cron.d/zz-ustar2`, `/.ustar5` and `/.ustar6` on XCP-ng hosts.
7. Vates: "These detection methods therefore only cover this specific campaign ... The absence of these IoCs alone is
   not sufficient to conclude that no compromise has occurred."

## Our advice (CybaVerse, not from Vates)

- Patch now, then hunt back to at least 1 Oct 2026. Exploitation can predate the fix and leaves no XO log.
- Revoke every XO authentication token after patching, not only passwords. The bypass reuses an existing token and the
  token route hands out reusable token IDs, so a stolen token may outlive a password change. (Vates names rotation of
  passwords and secrets; token revocation is our addition.)
- Rotate XCP-ng root passwords and any SSH keys on every pool XO manages, plus backup repository, S3 and proxy credentials.
- If XO sits behind a reverse proxy or WAF, turn on Cookie header logging for the XO site long enough to hunt, and match
  case-insensitive and encoded variants (KQL Q3 to Q5). Treat any `authenticationToken=j:` cookie as suspicious.
- Restrict the XO web interface to admin jump hosts or VPN ranges at the firewall, not only at the WAF.
- Inventory every XO and XOA instance across client estates, including old lab or migration appliances.

## Pack contents

| Path | What |
|---|---|
| `kql/xen-orchestra-vsa-2026-062-hunting.kql` | 13 hunts: Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q8b, Q9, Q10, Q11, Q12 |
| `sigma/*.yml` | 4 Sigma rules (proxy cookie, webserver cookie, C2 network connection, Linux campaign files) |
| `sigma/converted/` | Fresh `sigma convert -t kusto` output for `--without-pipeline`, `microsoft_xdr`, `microsoft_365_defender`, `sentinel_asim`, `azure_monitor` |
| `scripts/check-xen-orchestra.sh`, `scripts/Check-XenOrchestra.ps1` | Offline read-only checkers (bash and PowerShell, identical output) |
| `tests/` | Bash tests, Pester tests with parity, fixtures, KQL parse check, `run_all.sh` |

### KQL hunts

Tags: [VATES] = string, address or artefact from the Vates advisory. [OURS] = our own logic.

| ID | Table(s) | Hunt |
|---|---|---|
| Q1 | DeviceProcessEvents | [OURS] Find XO servers with Defender for Endpoint on Linux (xo-server processes) |
| Q2 | DeviceInfo, DeviceNetworkEvents | [OURS] XO servers internet facing or accepting inbound web traffic from public IPs |
| Q3 | CommonSecurityLog | [VATES strings, OURS variants] Empty-object cookie in WAF or proxy CEF logs |
| Q4 | W3CIISLog | [VATES strings, OURS variants] Same in IIS logs (needs csCookie logging) |
| Q5 | Syslog | [VATES strings, OURS variants] Same in proxy logs forwarded by syslog |
| Q6 | CommonSecurityLog, W3CIISLog, Syslog | [VATES path, OURS logic] Token listing route called from outside admin ranges (review list) |
| Q7 | DeviceNetworkEvents | [VATES IOC] Connections with 91.211.251.112 (port 8001 flagged) |
| Q8 | CommonSecurityLog | [VATES IOC] Same address in firewall, proxy or WAF logs |
| Q8b | Syslog | [VATES IOC] Same address in syslog |
| Q9 | DeviceNetworkEvents, CommonSecurityLog, DnsEvents | [VATES onion host, OURS Tor logic] Tor use from management hosts and the onion host |
| Q10 | DeviceFileEvents | [VATES] zz-ustar cron files, /.ustar5, /.ustar6 ([OURS] /etc/ld.so.preload as review only) |
| Q11 | Syslog | [VATES artefacts, OURS log route] XCP-ng dom0 syslog: `-serial file:`, hvm_serial file, pivot2, ustar names |
| Q12 | DeviceProcessEvents | [OURS] Shells or download tools started by xo-server |

Coverage limits: XO keeps no log of the bypass (Vates). Most access logs do not record cookies. XO usually serves HTTPS
directly, so network sensors only see the cookie where TLS ends at a proxy or WAF you control. Defender for Endpoint is
rarely on XCP-ng dom0, so for hypervisors run the Vates host checks and scan the saved output with the checker.

### Sigma conversion gaps (documented, enforced by run_all)

- `proxy_xo_empty_object_token_cookie.yml` and `web_xo_empty_object_token_cookie.yml` do not convert with `microsoft_xdr`,
  `microsoft_365_defender` or `azure_monitor` ("Unable to determine table name": no table for the proxy or webserver
  category) or with `sentinel_asim` (no mapping for `cs-cookie`). Use KQL Q3 to Q5.
- `azure_monitor` maps the two Linux rules to `SecurityEvent`, a Windows table. Treat that output as a template only.
- `--without-pipeline` output has no table name. Add the table yourself.

## Checker usage

Strictly read-only and offline. No network, no sockets, no file writes, no payloads, never contacts XO. They only
compare version strings and scan text files you saved.

```
scripts/check-xen-orchestra.sh --xo-server 5.213.1 --edition xoa --host xo-client-a
scripts/check-xen-orchestra.sh --csv inventory.csv
scripts/check-xen-orchestra.sh --scan proxy-access.log --scan xcpng-host1-checks.txt
pwsh scripts/Check-XenOrchestra.ps1 -Csv inventory.csv -Scan proxy-access.log
```

CSV header: `host,edition,xo_version,xo_server_version` (edition is `xoa` or `sources`; lines starting `#` are skipped).

`--scan` accepts proxy, WAF or web access logs, tcpdump text, firewall exports, and the saved output of the Vates host
checks (`xe vm-list params=name-label,platform`, `ls -la /etc/ld.so.preload /.ustar* /etc/cron.d/zz-ustar*`,
`zgrep -- '-serial file:' /var/log/xensource.log*`). Run those commands yourself on each XCP-ng host and save the output.
Lines reporting a missing file are skipped. Hits are tagged `[Vates IOC ...]` or `[ours ...]`; `NOTE` lines are review
items that do not change the exit code.

| Exit | Meaning |
|---|---|
| 0 | PATCHED (every row on a fixed xo-server build) |
| 1 | VULNERABLE (any row) |
| 2 | UNKNOWN (unreadable version or edition, no version given, or `--scan` alone with no match) |
| 3 | NEEDS MORE INFO (version label cannot prove the fix: XO 6.9.1 or 6.10.0 label only, sources 5.213.0, builds Vates did not name) |
| 4 | IOC MATCH (overrides 0 to 3) |
| 5 | Usage or read error |

Inventory modes exit with the worst row (1 > 2 > 3 > 0).

## IOCs and provenance

| Indicator | Source | Status |
|---|---|---|
| Cookie `authenticationToken=j:%7B%7D` | Vates advisory (detection and WAF sections) | Vendor published |
| Cookie `authenticationToken=j:{}` | Vates advisory | Vendor published |
| `91.211.251.112` (port 8001) | Vates advisory | Vendor published |
| `ustar3rqxgnskzgnwkgpofgtvxevm6cx3lxdbwt4mndtveqyaohid.onion` (port 3333, via Tor) | Vates advisory | Vendor published |
| VM named `pivot2` | Vates advisory | Vendor published |
| VM platform `hvm_serial: file`; `-serial file:` in xensource.log | Vates advisory | Vendor published |
| `/etc/cron.d/zz-ustar`, `/etc/cron.d/zz-ustar2`, `/.ustar5`, `/.ustar6` | Vates advisory | Vendor published |
| `/etc/ld.so.preload` | In the Vates `ls` check command, not named as an IOC | Review item only (ours) |
| Encoded or spaced cookie variants, other `/.ustar*` files, Tor ports | Our own patterns | Ours, not vendor IOCs |

No file hashes, user agents or additional addresses were published by Vates. We have not added any.

## Unverified

- The "5.213.2" in the Vates Affected Versions line (we read it as 5.211.2, see above).
- Whether stable channel xo-server 5.211.2 and latest 5.213.1 are visible in the public repository: neither tag was on
  GitHub `master` when checked, and the PR notes "Not run: stable backport validation". We rely on the Vates Resolution list.
- That every Xen Orchestra build after 5.213.1 keeps the fix (the checker returns NEEDS MORE INFO for builds Vates did not name).
- Our reading that an unexpired token must already exist for the bypass to work.
- Whether XCP-ng dom0 forwards the xensource lines Q11 needs in your estate (depends on your remote syslog setup).
- Exploitation timeline: Vates gives no first-seen date.

## Sources

Primary (fetched 10 Nov 2026, Europe/London):
- Vates VSA-2026-062: https://docs.vates.tech/security-advisories/advisories/2026/vates-sa-2026-062/ (HTTP 200, 17:04 GMT)
- Vates advisory index: https://docs.vates.tech/security-advisories/advisories/ (HTTP 200, 17:04 GMT)
- Xen Orchestra CHANGELOG (in the xen-orchestra source repository)
- Xen Orchestra updater docs: https://docs.xen-orchestra.com/getting-started/updater
- Xen Orchestra community docs (sources version check): https://docs.xen-orchestra.com/support-and-licensing/community
- Xen Orchestra blog: https://xen-orchestra.com/blog/ (HTTP 200, 17:04 GMT; no post on this issue at that time)
- CISA KEV JSON: https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json (catalog 2026.11.09)
- NVD CVE API keyword searches (Xen Orchestra, Vates, authenticationToken): https://services.nvd.nist.gov/rest/json/cves/2.0
- MITRE ATT&CK T1190, T1071, T1053.003: https://attack.mitre.org/

News (context only, not used for scores, versions or IOCs):
- BleepingComputer, "Critical Xen Orchestra auth bypass flaw exploited to hijack VM servers":
  https://www.bleepingcomputer.com/news/security/critical-xen-orchestra-auth-bypass-flaw-exploited-to-hijack-vm-servers/
  (HTTP 403 to our fetch at 17:04 and 17:06 GMT; read via search index snippet only. The headline calls it "Critical",
  and the article says a CVE and CVSS score have not been assigned yet.)
