____ _ _ ___ _____ _____ ____ _____ _____ _____ ____ / ___|| | | |_ _|_ _|_ _| _ \|_ _\ \/ /_ _| ____| _ \ \___ \| |_| || | | | | | | |_) || | \ / | || _| | |_) | ___) | _ || | | | | | | _ < | | / \ | || |___| _ < |____/|_| |_|___| |_| |_| |_| \_\___/_/\_\___|_____|_| \_\
Two weeks ago I published 89 CVEs in XAPI. The vendors' response was to patch 5, call the rest "AI hallucinations," accuse me of acting in bad faith, and refuse to credit me. This is the story of what they did and what they didn't do.
The vendors backported the XSA-489 fixes into XAPI 26.1.3-1.9 and 26.1.3-1.10. We ran the PoC suite against fully updated XCP-ng 8.3 (26.1.3-1.10) and verified the binaries. The results:
| CVE | Finding | CVSS | Vates severity | Result on fully updated XCP-ng 8.3 | Verified on |
|---|---|---|---|---|---|
| CVE-2026-23559 | BOC-1 | 9.9 | Low | FIXED - key still writable but xenopsd ignores it | target-5 (ext) + target-6 (LVM) |
| CVE-2026-23560 | VOC-1 | 4.3 | Low | FIXED - key writable but VBD sharing bypass blocked | target-5 + target-6 |
| CVE-2026-23561 | VOC-2 | 8.5 | Low | FIXED - key writable but pbd_of_vm returns None, DoS chain broken | target-5 + target-6 |
| CVE-2026-23562 | ARCH-4 | 8.5 | Low | Inconclusive - race not tipped under test conditions | target-5 + target-6 |
| CVE-2026-42486 | PLAT-6 | 8.6 | Low | FIXED - injection blocked by XAPI | target-5 + target-6 |
4 of the vendors' own 5 CVEs are actually fixed. The changelog says all 5. The PoCs say 4. And Vates classified every single one of them as severity Low in VSA-2026-011. As Low!
Rob Hoes wrote the fixes (PRs #7031-#7033) upstream. Pau Ruiz Safont at Vates backported them into the XCP-ng 8.3 package as 26.1.3-1.9. We re-verified: the keys can still be written (zero per-key RBAC) but the code that consumes them was removed, breaking the exploitation chains. The writes succeed but the values are now dead data.
Andriy Sultanov's fix (PR #7039, shipped as 26.1.3-1.10) works correctly. The hvm_serial injection is blocked. The one fix that was properly engineered - with a generic RBAC checker, not a code deletion - is the one that could scale to all 89 fields.
4 of 5 CVEs confirmed fixed. ARCH-4 inconclusive. Credit where it's due - the patches work. But 84 CVEs remain unaddressed.
On April 24, 2026, I published 89 CVEs in XAPI, the management stack behind Citrix XenServer and XCP-ng. 89 advisories backed by evidence logs from live exploitation tests.
On April 28, the Xen Project published XSA-489, assigning 5 CVEs. The advisory contains these statements:
"The researcher claimed 89 vulnerabilities. Analysis by the XAPI team concluded that only 5 were real vulnerabilities, with most being a failure to read the RBAC documentation, and several appearing to be AI hallucinations."
"The researcher also took active steps to prevent coordinated disclosure. Due to acting in bad faith, they are explicitly not credited."
This page documents how the vendors actually responded.
I contacted Vates (the XCP-ng maintainer) through every available channel before publishing:
| Date | Channel | Response |
|---|---|---|
| April 23 | Email to Vates with patch offer (19 upstream fixes) | None |
| April 23 | LinkedIn to Olivier Lambert (CEO, Vates) | None |
| April 23 | security@vates.tech | None |
Zero responses through any channel. Instead, "someone at XenServer looked at your profile" appeared on LinkedIn. Not someone from Vates. Someone from Citrix. Olivier received my outreach, didn't respond to me, and probably forwarded it to Citrix.
Rob Hoes (rob.hoes@citrix.com) and Andriy Sultanov (vates.tech) wrote the patches. First PR created 4 hours 52 minutes after disclosure. They used my findings. The advisory then refused to credit me.
Samuel Verschelde (stormi, XCP-ng Lead Maintainer) on the XCP-ng forum, April 27:
"We are aware of this publication and have reviewed every of its claims over the last days. A few of the reported issues do represent real privilege escalation paths."
Same "a few were real" framing that appeared word-for-word in the PGP-signed advisory the next day. His first response to a community member posting the disclosure link:
"@[redacted] Where did you find out about this site?"
Tracking the spread. Not investigating the findings.
| CVEs reported | 89 |
| CVEs assigned by vendor (XSA-489) | 5 |
| Actually fixed in code (v26.1.11) | 5 |
| CVE records published to MITRE/NVD | 0 |
| Fix shipped to XCP-ng 8.3 users | 4 working (changelog claims 5, PoCs confirm 4) |
| Credit given to researcher | 0 |
| Responses to researcher's outreach | 0 |
| Days since advisory (as of publication) | 10 |
| CVE | MOKSHA Advisory | Description | Fix PR |
|---|---|---|---|
| CVE-2026-23559 | BOC-1 | vm-admin mounts arbitrary host files as VDIs via VBD.other_config:backend-local | #7031 (removed code) |
| CVE-2026-23560 | VOC-1 | vm-admin marks VM as system domain via VM.other_config:is_system_domain | #7032 (removed code) |
| CVE-2026-23561 | VOC-2 | vm-admin disrupts PBD via VM.other_config:storage_driver_domain | #7033 (removed code) |
| CVE-2026-23562 | ARCH-4 | vm-admin accesses host hardware (PCI passthrough RBAC bypass) | #7039 (added RBAC) |
| CVE-2026-42486 | PLAT-6 | vm-admin writes arbitrary dom0 files via VM.platform:hvm_serial | #7039 (added RBAC) |
Every single CVE maps to a MOKSHA advisory. The vendors found nothing independently. All 5 fixes came from the researcher's disclosure. They relabeled the findings, assigned their own CVE numbers, and refused credit.
The fixes exist on GitHub. They were written in two different ways:
Rob Hoes (Citrix) took the nuclear option for 3 of the 5 CVEs: he deleted the code that reads the dangerous keys entirely. If XAPI no longer recognises backend-local, is_system_domain, or storage_driver_domain, nobody can abuse them. Simple, effective, breaks nothing - these keys were either obsolete or should never have been writable by a vm-admin in the first place.
Andriy Sultanov (Vates) took the engineering approach for the remaining 2: he built a per-key RBAC checker that restricts who can write specific keys. If you're a vm-admin and you try to set hvm_serial or pci in VM.other_config or VM.platform, XAPI now returns RBAC_PERMISSION_DENIED - only pool-admins can touch those keys. This is the fix that could scale to protect all 89 vulnerable fields if anyone extended it.
All 5 CVEs are fixed in the upstream source code. The backport to XCP-ng 8.3 tells a different story:
* Thu Apr 30 2026 Andrii Sultanov - 26.1.3-1.10 - More fixes for XSA-489 (CVE-2026-23562, CVE-2026-42486) * Mon Apr 27 2026 Pau Ruiz Safont - 26.1.3-1.9 - Fixes for XSA-489 (CVE-2026-23559, CVE-2026-23560, CVE-2026-23561)
The changelog claims all 5 CVEs are fixed. Our PoC verification confirms 4 of 5 (ARCH-4 inconclusive). Shipped as "routine maintenance" with no security flag, no urgency. 84 more RBAC violations remain unaddressed.
All 5 CVE numbers were checked against MITRE (cveawg API), NVD (services.nvd.nist.gov), and CVE.org on 2026-05-07. Result: CVE_RECORD_DNE for all 5. The CVE numbers exist only in the PGP-signed XSA-489 text. No published records. No descriptions. No CVSS scores. No credit field.
When a vulnerability is found, a CVE Numbering Authority (CNA) reserves a CVE number and then publishes a CVE record to the CVE.org database. Once published, the record automatically propagates to the National Vulnerability Database (NVD), vulnerability scanners (Nessus, Qualys, OpenVAS), and every security feed that enterprises use to track and patch vulnerabilities. This happens within hours. The CNA has a direct API - no queue, no approval needed.
The Xen Project is a CNA. They reserved 5 CVE numbers. They put them in a PGP-signed advisory. They never published the CVE records. Ten days later, all 5 return CVE_RECORD_DNE on MITRE, NVD, and CVE.org.
Without published records:
Think about what this means in practice. If you're a CISO running XCP-ng and you scan your infrastructure with Nessus, Qualys, or OpenVAS, these 5 CVEs come back clean. Not because they're patched on your systems - because the records don't exist in the scanner's feed. Your compliance dashboard shows green. Your audit report says no known vulnerabilities. The advisory exists in a PGP-signed text file on a mailing list that your scanner doesn't read.
The effect is the same whether it's negligence or strategy. Empty CVE records mean the vulnerability is invisible to the tooling that enterprises use to make patching decisions. No record, no alert, no urgency, no questions from management. The problem disappears - not because it's fixed, but because it can't be found.
Meanwhile, the 89 MOKSHA advisories have full CVE 5.1 JSON records at cna.moksha.dk. Searchable. Machine-readable. With CVSS scores. With descriptions. With references. The "hallucinations" are more real than the official CVEs.
Samuel Verschelde's defence: "we believe very few users are using it." The "it" is RBAC - Role Based Access Control. The mechanism that separates who can manage VMs from who can manage the host. The thing that every regulated environment requires.
"Very few users use it" because Xen Orchestra doesn't expose RBAC in its UI. That's a Vates product limitation, not a security assessment. XCPng-Center exposes full RBAC management and so does XenCenter. Enterprise customers who run XAPI with AD integration use RBAC daily. "Very few of our users" is not the same as "very few users" - it means Vates doesn't know its own enterprise customers.
Someone should tell Samuel about SSSD - it would probably blow his mind that enterprises have been integrating Linux hosts with Active Directory for RBAC for longer than Vates has existed. Any enterprise with AD integration, any MSP with multi-tenant access, any regulated environment with audit requirements uses RBAC. If Vates doesn't know that, they don't have enterprise customers. If they do know that and said it anyway, they're minimizing the disclosure at their users' expense.
Vates classified XSA-489 as severity Low in their own advisory, titled "Multiple XAPI potential Vulnerabilities". Potential. Not vulnerabilities - potential vulnerabilities. The PoCs run. /etc/shadow is readable. But sure - potential.
BOC-1 lets a vm-admin read /etc/shadow and the XAPI state.db (which contains API tokens, secrets, and the complete pool configuration). Root-equivalent access in seconds. CVSS 9.9. Severity: Low.
The CVSS score and the vendor's severity rating are not in the same category.
SMC-1 (CVSS 9.9) - silent injection of arbitrary commands into iSCSI, NFS, and Fibre Channel traffic - lives in _override_sm_config at VDI.py line 498. This function is not a bug. It IS the architecture.
Every SMAPIv2 storage driver (LVM, NFS, iSCSI, ext, GFS2) depends on _override_sm_config to reconcile storage metadata. If they validate or restrict this function, every storage driver breaks. Every existing installation loses storage.
SMC-1 is not mentioned in XSA-489. Not patched. Not addressed. Not disputed. Absent.
Let me be clear: SMC-1 is out there. It has been out there long before I found it - anyone who has ever read VDI.py line 498 knows what _override_sm_config does. And it will never get patched because patching it breaks every SMAPIv2 storage driver on every XAPI installation in the world. The only way out is SMAPIv3 - and looking at Vates' ZFS driver for SMAPIv3 (qcow2 on top of ZFS, using raw zpools instead of datasets, with a coalesce process, on a filesystem designed to make coalescing unnecessary), I have absolutely no hope for this platform. That's not a migration path. That's a dead end.
And if you're thinking "maybe XCP-ng 9.0 will fix this" - I've looked. It doesn't. Same ethics, same lax security posture, same failure to understand that map field validation isn't optional. 9.0 is a continuation, not a correction. New kernel, same architecture, same _override_sm_config, same SMAPIv2 NFS/iSCSI drivers, same unvalidated trust boundaries. A fresh coat of paint on the same broken foundation.
The only way out is if someone picks up the gauntlet and builds a fully locked-down XAPI hypervisor with native ZFS, iSCSI, and NFS drivers on SMAPIv3 - no _override_sm_config, no VHD chains, no coalesce, no qcow2 wrapping. Raw zvols. Native snapshots. Input validation on every map field. The architecture done right from the ground up. Let's hope someone is doing exactly that.
In the original disclosure, section 12 explained why I didn't give Citrix advance notice. I wrote about their history of dismissing security researchers, their pattern of minimal patches, their institutional culture of treating disclosure as a PR problem rather than an engineering one.
People told me I was being unfair. That I was too aggressive. That responsible disclosure means giving the vendors every chance.
I gave Vates every chance. Three channels. 19 free patches. A conditional offer to transfer the fix set. Zero responses. And then Citrix appeared on my LinkedIn - the exact company I warned about - and the two of them together produced an advisory calling my work "AI hallucinations."
I am a sysadmin. I run FreeBSD. I run Linux. I run ZFS. I run Xen, VMware and KVM as well. I found these bugs because I wanted to write a storage driver and I read the code and the code was broken. I reported what I found. I offered patches. I contacted every responsible party I could find. Citrix doesn't even have a security@ address - there is no way to report vulnerabilities to them. And the response was silence, then dismissal, then a PGP-signed document accusing me of bad faith.
I was right about Citrix. I was wrong to think Vates would be different.
If Olivier Lambert had written back - even one line - "wow, that looks bad - can we talk about this?" - any sane person would freeze the disclosure on the spot. I know I would have. That's all it would have taken. Olivier Lambert had my email, we were connected on LinkedIn where I was messaging him repeatedly, and he had security@vates.tech. He had every chance to respond, to ask questions, to understand why I was adamant about not disclosing to Citrix myself. He chose silence. Then Citrix appeared on my LinkedIn.
So I did what I knew was right: I published. Silence from the vendors doesn't reduce urgency - it increases it.
Before publishing, I contacted MITRE, CERT/CC, GCVE, CIRCL, ENISA, DIVD, and Vates directly with 19 free patches and an open offer to coordinate. The response from the vendors was silence, then a PGP-signed advisory calling the findings "AI hallucinations" and the researcher "bad faith." They used the findings, wrote the patches, assigned CVE numbers, and then signed a document calling the work fake.
The ethical move was to publish. The moral move was to publish. Users deserve to know what's running on their infrastructure. They deserve to know that the vendors dismissed 84 of 89 findings without addressing them. They deserve to know that the mechanism to prevent all 89 vulnerabilities existed in the codebase since 2009 and was used only to protect licensing and GUI keys in 17 years. They deserve the truth, even when the truth is uncomfortable for the people who sell them software.
I'm not sorry. I'd do it again.
Publishing the PoC library gives me no pleasure. The poc_lib.py framework is fissile material - point an LLM at the library and the 89 advisories and you have a factory for weaponized exploits against XAPI installations. I held this back as long as I could.
The response to the disclosure - detailed above - forced this hand.
I am publishing the PoC library and all 4 confirmed-fixed XSA-489 CVEs. Standard practice for acknowledged, patched, verified-fixed vulnerabilities.
poc_lib.py - the shared PoC framework (1,886 lines)boc-1-poc.py - BOC-1 (CVE-2026-23559) - arbitrary host device mountvoc-1-is-system-domain.py - VOC-1 (CVE-2026-23560) - system domain privilege escalationvoc-2-storage-driver-domain.py - VOC-2 (CVE-2026-23561) - storage driver domain PBD injectionplat-6-hvm-serial.py - PLAT-6 (CVE-2026-42486) - QEMU serial host filesystem writeThe library is the framework. The 89 advisories are the map. The 4 published PoCs are the examples. The remaining 84 unaddressed RBAC violations are left as an exercise for the reader - or for any LLM with access to poc_lib.py and the advisory descriptions at cna.moksha.dk.
Download shittrixier-poc-v1.1.zip
If you are a CSIRT, contact me for the full PoC suite.
yum update (26.1.3-1.10). The remaining 84 CVEs have no vendor patch.The complete timeline with exact timestamps, the timing analysis, the 17-year map_keys_roles gap, and everything that doesn't add up: shittrixier.moksha.dk/timeline
Jakob Wolffhechel
Moksha - Copenhagen
jakob@wolffhechel.dk
GNA #117 - cna.moksha.dk