MOKSHA-2026-0078: Guest Clock Manipulation via VDI.other_config timeoffset

Advisory IDMOKSHA-2026-0078
Semantic IDDOC-6
Published2026-04-24
CVSS 3.14.3 Medium
CVSS 3.1 VectorAV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
CVSS 4.02.3 Low
CVSS 4.0 VectorAV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N
XAPI ObjectVDI
XAPI Fieldother_config:timeoffset
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 in XAPI-based hypervisors (XenServer, XCP-ng) can manipulate the guest VM's RTC clock by setting the timeoffset key in VDI.other_config. When a VDI has on_boot=reset, the timeoffset value from VDI.other_config overrides the VM's platform-level timeoffset setting during domain creation (xapi_xenops.ml:312-327). Arbitrary strings are accepted - no type validation enforces the expected integer format. A corrupted timeoffset causes the guest OS to boot with an incorrect clock, affecting Windows license validation, certificate expiration checks, Kerberos authentication, scheduled task execution, and audit trail integrity. The VDI.other_config field has no map_keys_roles entries for infrastructure keys.

Vulnerability Description

VDI.other_config is a Map(String, String) field defined at datamodel.ml:6310-6315 with _R_VM_ADMIN as the minimum write role.

The timeoffset override logic at xapi_xenops.ml:312-327:

let rtc_timeoffset_of_vm ~__context ~vm =
  ...
  if vdi.API.vDI_on_boot = `reset then
    match
      (List.assoc_opt Vm_platform.timeoffset record.API.vDI_other_config)
    with
    | Some timeoffset -> timeoffset
    | None -> ...

When a VDI has on_boot=reset (common for snapshot-based VDIs), the timeoffset from VDI.other_config takes precedence over the VM platform setting. The value is expected to be an integer string representing the RTC offset in seconds from UTC, but no validation enforces this:

The attack requires the target VDI to have on_boot=reset set. This is common in environments using non-persistent VDIs or snapshot-based provisioning.

Root Causes

  1. Missing type validation. The timeoffset value is expected to be an integer but any string is accepted without validation at write time.

  2. Missing RBAC protection. VDI.other_config has map_keys_roles entries only for UI keys (folder, XenCenter.CustomFields.*). The timeoffset key is writable by any vm-admin.

  3. VDI-level override of VM-level setting. The VDI.other_config timeoffset overrides the VM.platform timeoffset when on_boot=reset. This creates a secondary control path that bypasses any validation applied to the VM.platform field.

  4. set_other_config RBAC bypass. The set_other_config method replaces the entire map atomically and bypasses map_keys_roles per-key checks.

Affected Systems

Directly Affected

Indirectly Affected

Exploitation Scenarios

Scenario Impact Pre-conditions Status
Clock shift forward Windows license validation fails, certificates appear expired vm-admin, VDI with on_boot=reset Source-traced
Clock shift backward Kerberos authentication fails (clock skew), scheduled tasks delayed vm-admin, VDI with on_boot=reset Source-traced
Audit trail corruption Log entries have incorrect timestamps, breaking forensic timeline vm-admin, VDI with on_boot=reset Modeled
BOC-1 chain vm-admin corrupts timeoffset on all reset-boot VDIs pool-wide vm-admin, BOC-1 Source-traced

Chaining Analysis

Detection

Remediation

Short-Term Mitigations

Long-Term Fix

Add write-time validation. Validate that timeoffset is a valid integer within a reasonable range (e.g., -86400 to 86400 seconds).

Add map_keys_roles protection. Restrict the timeoffset key to _R_POOL_ADMIN in datamodel.ml.

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