MOKSHA-2026-0089: Raw kbps Value Exposure in Private Xenstore via VIF.qos_algorithm_params

Advisory IDMOKSHA-2026-0089
Semantic IDVQP-5
Published2026-04-24
CVSS 3.12.3 Low
CVSS 3.1 VectorAV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N
CVSS 4.05.3 Medium
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 ObjectVIF
XAPI Fieldqos_algorithm_params:kbps (xenstore)
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 set VIF.qos_algorithm_params:kbps, which xenopsd writes as a raw Int64.to_string value to the VIF's private xenstore path at device.ml:920-927. The raw kbps and timeslice_us values are stored at /xapi/<domid>/private/vif/<devid>/rate and .../timeslice for xenopsd internal bookkeeping (VIF replug scenarios). While Int64.to_string prevents xenstore path injection (it produces only decimal digit characters), the raw user-controlled values are readable by dom0 processes that consume VIF private xenstore data. The VIF.qos_algorithm_params field has zero map_keys_roles entries.

Vulnerability Description

VIF.qos_algorithm_params is a Map(String, String) field defined at datamodel.ml:1666-1681 via the qos function with zero map_keys_roles entries.

xenopsd writes raw rate values to two xenstore locations:

Backend path (device.ml:851) - computed bytes_per_interval:

rate = sprintf "%Lu,%Lu" bytes_per_interval timeslice_us
Written to: /local/domain/0/backend/vif/<domid>/<devid>/rate

Private data path (device.ml:920-927) - raw user-controlled values:

match rate with
| None -> []
| Some (rate, timeslice) ->
    [ ("rate", Int64.to_string rate)
    ; ("timeslice", Int64.to_string timeslice) ]

Written to: /xapi/<domid>/private/vif/<devid>/rate and .../timeslice

The private path stores the raw kbps and timeslice_us values from the user, not the computed bytes_per_interval. These are formatted via Int64.to_string, which produces only decimal digit characters (optionally with a leading - for negative values).

The private xenstore path is readable only by dom0 processes. There is no guest-side visibility. Int64.to_string formatting prevents xenstore path separator injection or other injection attacks through this path.

The concern is the architectural pattern: user-controlled values from a vm-admin are stored in a dom0-readable location without any indication that they are attacker-supplied rather than system-generated.

Root Causes

  1. Raw value passthrough. xenopsd stores the raw user-provided kbps and timeslice_us in private xenstore without marking them as user-supplied or validating them.

  2. Missing RBAC protection. VIF.qos_algorithm_params has zero map_keys_roles entries. All keys are writable by vm-admin.

  3. No provenance tracking. Dom0 processes that read the private xenstore path cannot distinguish between values set by XAPI internally and values injected by a vm-admin.

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

Affected Systems

Directly Affected

Indirectly Affected

Exploitation Scenarios

Scenario Impact Pre-conditions Status
Raw value in private xenstore Attacker-controlled kbps value readable by dom0 processes vm-admin, VIF with ratelimit QoS Live-tested
Replug with stored value xenopsd re-reads raw kbps from private xenstore on replug vm-admin, VIF replug Source-traced
Negative kbps in xenstore Negative Int64 value stored as "-N" string in xenstore vm-admin Source-traced

Chaining Analysis

Detection

Remediation

Short-Term Mitigations

Long-Term Fix

Validate before storing. Apply the same range validation to the private xenstore write path as the backend xenstore path. Do not store raw user-controlled values that failed validation.

Add provenance markers. Mark private xenstore values as validated or unvalidated so downstream consumers can distinguish system-generated from user-supplied data.

Add write-time validation for kbps. Reject invalid kbps values at the XAPI API boundary before they propagate to xenopsd and xenstore.

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