CHAP authentication credentials for iSCSI storage connections in XAPI-based hypervisors (XenServer, XCP-ng) are stored in PBD.device_config as chapuser (plaintext username) and chappassword_secret (an XAPI secret reference). Any pool-operator can read the PBD record to obtain the chapuser and the secret reference, then call secret.get_value() to resolve the cleartext password. This enables cross-user credential theft: one pool-operator creates an iSCSI SR with CHAP credentials, and a different pool-operator in the same pool recovers the cleartext password via the XAPI secret resolution path. The credentials are also stored in plaintext in the XAPI database (state.db) on disk, accessible via BOC-1 filesystem read.
PBD.device_config is the storage connection string for SM drivers. For iSCSI SRs, it carries CHAP authentication parameters:
chapuser - stored as plaintext in the PBD recordchappassword - legacy plaintext password field (still accepted)chappassword_secret - reference to an XAPI secret object containing the passwordincoming_chapuser / incoming_chappassword - mutual CHAP credentialsThe credential exposure path:
pool-operator-A creates an iSCSI SR with CHAP credentialschapuser in plaintext in the PBD recordchappassword_secret as a secret reference (e.g., OpaqueRef:abc123)pool-operator-B reads the PBD record: PBD.get_device_config(pbd) returns chapuser and chappassword_secretpool-operator-B calls secret.get_value(OpaqueRef:abc123) to resolve the cleartext passwordpool-operator-B now has the CHAP credentials for the storage arrayThe secret resolution path has no ownership check. Any pool-operator can resolve any XAPI secret, regardless of who created it.
Plaintext credential storage. CHAP usernames are stored in plaintext in device_config. The password uses a secret reference, but the reference is readable by any pool-operator.
Missing secret ownership model. XAPI secrets have no ownership or access control beyond the minimum role for secret.get_value(). Any session with pool-operator can resolve any secret.
Cross-user credential access. The RBAC model permits one pool-operator to read credentials created by another pool-operator. There is no per-user or per-SR isolation of credentials.
On-disk plaintext storage. The XAPI database (state.db) stores credentials in plaintext. BOC-1 filesystem read (MOKSHA-2026-0001, S2) directly exposes them.
| Scenario | Impact | Pre-conditions | Status |
|---|---|---|---|
| Cross-user credential theft | pool-operator-B recovers CHAP credentials created by pool-operator-A | Two pool-operators in same pool, iSCSI SR with CHAP | Confirmed (live-tested, ALL PASS) |
| Storage array unauthorized access | Stolen CHAP credentials used to access storage array directly | pool-operator, iSCSI SR with CHAP, network access to storage | Modeled |
| Credential reuse attack | CHAP credentials reused across multiple systems enable lateral movement | pool-operator, CHAP credential reuse in environment | Modeled |
| BOC-1 filesystem read | vm-admin reads state.db via BOC-1 S2, extracts plaintext CHAP credentials | vm-admin, BOC-1, iSCSI SR with CHAP | Source-traced |
PDC-4 chains with BOC-1 and PDC-1/PDC-6:
state.db from the host filesystem, extracting all CHAP credentials without needing API access.secret.get_value() API calls for unusual access patterns (e.g., pool-operator resolving secrets they did not create)chappassword (legacy field that should not be used)state.db from non-XAPI processesdisclosure/vendor-detection-guidance.mdchappassword to chappassword_secretsecret.get_value() API calls for unauthorized accessCredential isolation. Implement per-user or per-SR secret ownership. A pool-operator should only be able to resolve secrets they created or secrets associated with SRs they manage.
Deprecate plaintext credentials. Reject chappassword (plaintext) in device_config. Require chappassword_secret for all CHAP configurations.
Encrypt state.db credentials. CHAP credentials in the XAPI database should be encrypted at rest, not stored as plaintext.
Upstream patches exist. They are held privately pending coordinated disclosure.
Disclosure:
BaseISCSI.py:181-197 (CHAP credential read from device_config), SRCommand.py:94 (dconf passthrough)disclosure/advisories/pdc-security-advisory.md (PDC-4)research/investigations/pbd-device-config.mdresearch/pdc-4/poc/pdc-4-chap-credential-exposure.py (available to CSIRTs on request)Discovered and reported by Jakob Wolffhechel, Moksha.