MOKSHA-2026-0020: CBT Metadata Corruption via VDI.other_config content_id

Advisory IDMOKSHA-2026-0020
Semantic IDDOC-4
Published2026-04-24
CVSS 3.17.1 High
CVSS 3.1 VectorAV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:N
CVSS 4.08.3 High
CVSS 4.0 VectorAV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:N/SI:H/SA:N
XAPI ObjectVDI
XAPI Fieldother_config:content_id
Entry Rolevm-admin
ResearcherJakob Wolffhechel, Moksha

Affected Products

VendorProductVersions
Citrix / Cloud Software GroupXenServer / Citrix Hypervisorall versions (shared XAPI codebase)
VatesXCP-ng8.3.0

Summary

A vm-admin can corrupt Change Block Tracking (CBT) metadata by injecting a crafted content_id value into VDI.other_config. The content_id key is used by the XAPI storage bridge (storage_smapiv1.ml) to track VDI content identity across activate/deactivate/clone cycles. Incremental backup solutions use content_id to determine the base snapshot for changed-block calculations. A forged UUID causes the backup system to use an incorrect base, missing changed blocks and producing backups that silently lose data on restore. The attack requires a single API call and produces no security alerts.

Vulnerability Description

VDI.other_config is a Map(String, String) field writable by vm-admin. The content_id key participates in a lifecycle managed by the XAPI storage bridge.

content_id Lifecycle

(* storage_smapiv1.ml *)

(* VDI.activate (RW): remove content_id - content is about to change *)
Db.VDI.remove_from_other_config ~__context ~self ~key:"content_id"   (* line 524-525 *)

(* VDI.deactivate: generate new content_id - content is now stable *)
if not (List.mem_assoc "content_id" other_config) then
  Db.VDI.add_to_other_config ~__context ~self ~key:"content_id"
    ~value:Uuidx.(to_string (make ()))                               (* line 557-559 *)

(* VDI.clone: inherit content_id from parent - same content *)
let content_id =
  List.assoc "content_id"
    (Db.VDI.get_other_config ~__context ~self:clonee)                (* line 682-684 *)

Attack Mechanism

The content_id value has no format validation. A vm-admin can:

  1. Forge a content_id. Set content_id to match a different VDI's identity. The backup system treats the VDIs as having identical content when they do not, causing the incremental backup to skip blocks that have changed.

  2. Remove content_id. Force XAPI to regenerate a new UUID on the next deactivate cycle, breaking the chain of identity that backup systems rely on for incremental tracking.

  3. Set an invalid content_id. Inject a non-UUID string that may cause parsing failures in backup systems that expect UUID format.

Impact on Incremental Backups

CBT-based incremental backup works by comparing the current VDI's content_id against the base snapshot's content_id. If they match, the backup system assumes the content is identical and only tracks blocks changed since the snapshot. A forged content_id that matches a stale or incorrect base causes the backup to:

Root Causes

  1. Missing RBAC protection. VDI.other_config has zero map_keys_roles entries for content_id. Any vm-admin can modify it.

  2. No format validation. The content_id value is accepted as any arbitrary string. No UUID format enforcement, no check against known VDI identities.

  3. Backend trust assumption. The XAPI storage bridge assumes content_id is only modified by XAPI's own lifecycle code. No mechanism distinguishes XAPI-set values from user-injected values.

  4. Silent failure mode. Backup systems that rely on content_id for incremental tracking have no way to detect a forged value. The corruption is silent until a restore reveals missing data.

Affected Systems

Directly Affected

Indirectly Affected

Exploitation Scenarios

Scenario Impact Pre-conditions Status
content_id forgery Incremental backups miss changed blocks, silent data loss on restore CBT-enabled VDI, backup system using content_id Confirmed (injection path code-traced; content_id lifecycle verified in storage_smapiv1.ml)
content_id removal Backup chain broken, forces full backup or causes backup failure CBT-enabled VDI Modeled (follows from lifecycle analysis)
Cross-VDI identity collision Two VDIs with same content_id, backup system may confuse them Multiple VDIs under backup Modeled
Bulk corruption via BOC-1 Root access enables bulk content_id modification across all VDIs in the pool BOC-1 available Modeled (amplification chain)

Detection

Remediation

Short-Term Mitigations

Long-Term Fix

Add map_keys_roles. Protect content_id in datamodel.ml at _R_POOL_ADMIN to prevent vm-admin from modifying it.

Format validation. Enforce UUID format when content_id is set via the API. Reject non-UUID values.

Internal-only flag. Mark content_id as an internally-managed key that should not be writable through external API calls. The XAPI storage bridge should be the only writer.

Upstream patches exist. They are held privately pending coordinated disclosure.

Disclosure

Disclosure:

References

Credits

Discovered and reported by Jakob Wolffhechel, Moksha.

Jakob Wolffhechel · Moksha · Copenhagen
jakob@wolffhechel.dk · +45 3170 7337
Published 2026-04-24 08:00 CEST · cna.moksha.dk · shittrix.moksha.dk