XML External Entity (XXE) Injection
Description
The package glances before 3.2.1 are vulnerable to XML External Entity (XXE) Injection via the use of Fault to parse untrusted XML data, which is known to be vulnerable to XML attacks.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Glances before 3.2.1 is vulnerable to XML External Entity (XXE) injection, potentially allowing remote attackers to read arbitrary files or perform SSRF attacks via crafted XML data.
Vulnerability
Glances versions before 3.2.1 contain an XML External Entity (XXE) injection vulnerability [1][2]. The Fault class from the standard library is used to parse untrusted XML data without disabling DT processing, making the tool susceptible to XML attacks. This affects the client/server mode where XML-RPC or similar XML-based data exchange may occur [1].
Exploitation
An attacker needs network access to the Glances server or the ability to supply crafted XML data to the client/server interface. By sending a malicious XML payload containing an external entity reference, the attacker can trigger the XXE. No authentication is required if the service is exposed without proper access controls. The vulnerability is triggered when the vulnerable code parses the XML input using the default Fault parser, which does not disable external entity resolution.
Impact
Successful exploitation allows an attacker to read arbitrary files from the server filesystem, perform server-side request forgery (SSRF) attacks, or cause denial of service via entity expansion. This can lead to disclosure of sensitive information or internal network reconnaissance. The compromise scope depends on the server's file permissions and network configuration.
Mitigation
The vulnerability is fixed in Glances version 3.2.1 [1][3]. The fix involved adding a secure_popen function and likely sanitizing XML parsing (as indicated by the security audit commit [4]). Users should upgrade to version 3.2.1 or later. For systems that cannot be immediately upgraded, restrict network access to the Glances service to trusted hosts only and avoid exposing the XML-RPC endpoint to untrusted networks.
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
GlancesPyPI | < 3.2.1 | 3.2.1 |
Affected products
2- glances/glancesdescription
Patches
39d6051be4a42Security audit - B411 #1025
5 files changed · +21 −3
glances/compat.py+8 −0 modified@@ -44,6 +44,10 @@ from urllib.error import HTTPError, URLError from urllib.parse import urlparse + # Correct issue #1025 by monkey path the xmlrpc lib + from defusedxml.xmlrpc import monkey_patch + monkey_patch() + input = input range = range map = map @@ -132,6 +136,10 @@ def system_exec(command): from urllib2 import urlopen, HTTPError, URLError from urlparse import urlparse + # Correct issue #1025 by monkey path the xmlrpc lib + from defusedxml.xmlrpc import monkey_patch + monkey_patch() + input = raw_input range = xrange ConfigParser.read_file = ConfigParser.readfp
optional-requirements.txt+1 −1 modified@@ -10,7 +10,7 @@ docker>=2.0.0 elasticsearch graphitesender hddtemp -influxdb +influxdb>=1.0.0 influxdb-client; python_version >= "3.6" kafka-python netifaces
README.rst+6 −0 modified@@ -59,13 +59,19 @@ Requirements - ``python>=2.7`` or ``python>=3.4`` - ``psutil>=5.3.0`` (better with latest version) +- ``defusedxml`` (in order to monkey path xmlrpc) +- ``future`` (for Python 2 support) *Note for Python 2.6 users* Glances no longer supports Python 2.6. Please upgrade to a minimum Python version of 2.7/3.4+ or downgrade to Glances 2.6.2 (last version with Python 2.6 support). +*Deprecation warning note for Python 2.x users* + +Glances version 4.0 will no longer supports Python 2.x. + Optional dependencies: - ``bernhard`` (for the Riemann export module)
requirements.txt+1 −0 modified@@ -1,2 +1,3 @@ psutil>=5.3.0 +defusedxml future
setup.py+5 −2 modified@@ -41,7 +41,7 @@ def get_data_files(): def get_install_requires(): - requires = ['psutil>=5.3.0', 'future'] + requires = ['psutil>=5.3.0', 'defusedxml', 'future'] if sys.platform.startswith('win'): requires.append('bottle') requires.append('requests') @@ -60,7 +60,6 @@ def get_install_extras_require(): 'paho-mqtt', 'potsdb', 'prometheus_client', 'pyzmq', 'statsd'], 'folders': ['scandir'], # python_version<"3.5" - 'gpu': ['py3nvml'], 'graph': ['pygal'], 'ip': ['netifaces'], 'raid': ['pymdstat'], @@ -70,6 +69,10 @@ def get_install_extras_require(): 'web': ['bottle', 'requests'], 'wifi': ['wifi'] } + if PY3: + extras_require['export'].append('influxdb-client') + extras_require['gpu'] = ['py3nvml'] + # Add automatically the 'all' target extras_require.update({'all': [i[0] for i in extras_require.values()]})
4b87e979afdcAdd NEWS file and improve Makefile
2 files changed · +55 −7
Makefile+3 −1 modified@@ -58,6 +58,8 @@ profiling: venv venv-dev @echo "Please complete and run: sudo ./venv/bin/py-spy record -o ./docs/_static/glances-flame.svg -d 60 -s --pid <GLANCES PID>" release-note: - git --no-pager log $(LASTTAG)..HEAD --first-parent --pretty=format:"* %s (by %an)" + git --no-pager log $(LASTTAG)..HEAD --first-parent --pretty=format:"* %s" + echo "" + git --no-pager shortlog -s -n $(LASTTAG)..HEAD .PHONY: test docs docs-server
NEWS.rst+52 −6 modified@@ -1,15 +1,61 @@ ============================================================================== -Glances Version 3 + Glances changelog ============================================================================== =============== -Version 3.1.8 +Version 3.2.0 =============== Under Development. See roadmap here ==> https://github.com/nicolargo/glances/milestone/49 +This release is a major version (but minor number because the API did not change). It focus on +*CPU consumption*. I use `Flame profiling https://github.com/nicolargo/glances/wiki/Glances-FlameGraph`_ +and code optimization to reduce CPU consumption from 20% to 50% depending on your system. + +Enhancement and development requests: + + * Improve CPU consumption + - Make the refresh rate configurable per plugin #1870 + - Add caching for processing username and cmdline + - Correct and improve refresh time method + - Set refresh rate for global CPU percent + - Set the dafault refresh rate of system stats to 60 seconds + - Default refresh time for sensors is refresh rate * 2 + - Improve history perf + - Change main curses loop + - Improve Docker client connection + - Update Flame profiling + * Get system sensors temperatures thresholds #1864 + * Filter data exported from Docker plugin + * Make the Docker API connection timeout configurable + * Add --issue to Github issue template + * Add release-note in the Makefile + * Add some comments in cpu_percent + * Add some comments to the processlist.py + * Set minimal version for PSUtil to 5.3.0 + * Add comment to default glances.conf file + * Improve code quality #820 + * Update WebUI for security vuln + +Bugs corrected: + + * Quit from help should return to main screen, not exit #1874 + * AttributeError: 'NoneType' object has no attribute 'current' #1875 + * Merge pull request #1873 from metayan/fix-history-add + * Correct filter + * Correct Flake8 issue in plugins + * Pressing Q to get rid of irq not working #1792 + +Contibutors for this version: + + * Nicolargo + * Markus Pöschl + * Clifford W. Hansen + * Blake + * Yan + =============== Version 3.1.7 =============== @@ -45,7 +91,7 @@ Version 3.1.6.2 Bugs corrected: - * Remove bad merge for a non tested feature(see https://github.com/nicolargo/glances/issues/1787#issuecomment-774682954) + * Remove bad merge for a non tested feature (see https://github.com/nicolargo/glances/issues/1787#issuecomment-774682954) Version 3.1.6.1 =============== @@ -74,8 +120,8 @@ Enhancements and new features: Bugs corrected: - * Version tag for docker image packaging #1754 - * Unusual characters in cmdline cause lines to disappear and corrupt the display #1692 + * Version tag for docker image packaging #1754 + * Unusual characters in cmdline cause lines to disappear and corrupt the display #1692 * UnicodeDecodeError on any command with a utf8 character in its name #1676 * Docker image is not up to date install #1662 * Add option to set the strftime format #1785 @@ -117,7 +163,7 @@ Enhancements and new features: Bugs corrected: * Can't start server: unexpected keyword argument 'address' bug enhancement #1693 - * class AmpsList method _build_amps_list() Windows fail (glances/amps_list.py) bug #1689 + * class AmpsList method _build_amps_list() Windows fail (glances/amps_list.py) bug #1689 * Fix grammar in sensors documentation #1681 * Reflect "used percent" user disk space for [fs] alert #1680 * Bug: [fs] plugin needs to reflect user disk space usage needs test #1658
85d5a6b4af31Security audit - B411 #1025
4 files changed · +90 −8
glances/actions.py+9 −6 modified@@ -19,10 +19,9 @@ """Manage on alert actions.""" -from subprocess import Popen - from glances.logger import logger from glances.timer import Timer +from glances.secure import secure_popen try: import chevron @@ -94,12 +93,16 @@ def run(self, stat_name, criticity, commands, repeat, mustache_dict=None): logger.info("Action triggered for {} ({}): {}".format(stat_name, criticity, cmd_full)) - logger.debug("Action will be executed with the following command: \ - subprocess.Popen({}, shell=False)".format(cmd_full.split(' '))) try: - Popen(cmd_full.split(' '), shell=False) + ret = secure_popen(cmd_full) except OSError as e: - logger.error("Can't execute the action ({})".format(e)) + logger.error("Action error for {} ({}): {}".format(stat_name, + criticity, + e)) + else: + logger.debug("Action result for {} ({}): {}".format(stat_name, + criticity, + ret)) self.set(stat_name, criticity)
glances/config.py+1 −1 modified@@ -293,7 +293,7 @@ def get_value(self, section, option, If it did not exist, then return the default value. It allows user to define dynamic configuration key (see issue#1204) - Dynamic vlaue should starts and end with the ` char + Dynamic value should starts and end with the ` char Example: prefix=`hostname` """ ret = default
glances/secure.py+73 −0 added@@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +# +# This file is part of Glances. +# +# Copyright (C) 2021 Nicolargo <nicolas@nicolargo.com> +# +# Glances is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Glances is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +"""Secures functions for Glances""" + +from glances.compat import nativestr +from subprocess import Popen, PIPE + + +def secure_popen(cmd): + """A more or less secure way to execute system command + + Return: the result of the command OR an error message + """ + ret = None + + # Split by redirection '>' + cmd_split_redirect = cmd.split('>') + if len(cmd_split_redirect) > 2: + return 'Glances error: Only one file redirection allowed ({})'.format(cmd) + elif len(cmd_split_redirect) == 2: + stdout_redirect = cmd_split_redirect[1].strip() + cmd = cmd_split_redirect[0] + else: + stdout_redirect = None + + sub_cmd_stdin = None + p_last = None + # Split by pipe '|' + for sub_cmd in cmd.split('|'): + # Split by space ' ' + sub_cmd_split = [i for i in sub_cmd.split(' ') if i] + p = Popen(sub_cmd_split, + shell=False, + stdin=sub_cmd_stdin, + stdout=PIPE, + stderr=PIPE) + if p_last is not None: + # Allow p_last to receive a SIGPIPE if p exits. + p_last.stdout.close() + p_last = p + sub_cmd_stdin = p.stdout + + p_ret = p_last.communicate() + + if nativestr(p_ret[1]) == '': + # No error + ret = nativestr(p_ret[0]) + if stdout_redirect is not None: + # Write result to redirection file + with open(stdout_redirect, "w") as stdout_redirect_file: + stdout_redirect_file.write(ret) + else: + # Error + ret = nativestr(p_ret[1]) + + return ret
unitest.py+7 −1 modified@@ -35,11 +35,11 @@ from glances.thresholds import GlancesThresholds from glances.plugins.glances_plugin import GlancesPlugin from glances.compat import subsample, range +from glances.secure import secure_popen # Global variables # ================= - # Init Glances core core = GlancesMain() @@ -376,6 +376,12 @@ def test_099_output_bars_must_be_between_0_and_100_percent(self): bar.percent = 101 self.assertGreaterEqual(bar.percent, bar.max_value) + def test_100_secure(self): + """Test secure functions""" + print('INFO: [TEST_100] Secure functions') + self.assertEqual(secure_popen('echo -n TEST'), 'TEST') + self.assertEqual(secure_popen('echo FOO | grep FOO'), 'FOO\n') + def test_999_the_end(self): """Free all the stats""" print('INFO: [TEST_999] Free the stats')
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
8- github.com/advisories/GHSA-r2mj-8wgq-73m6ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2021-23418ghsaADVISORY
- github.com/nicolargo/glances/commit/4b87e979afdc06d98ed1b48da31e69eaa3a9fb94ghsax_refsource_MISCWEB
- github.com/nicolargo/glances/commit/85d5a6b4af31fcf785d5a61086cbbd166b40b07aghsax_refsource_MISCWEB
- github.com/nicolargo/glances/commit/9d6051be4a42f692392049fdbfc85d5dfa458b32ghsax_refsource_MISCWEB
- github.com/nicolargo/glances/issues/1025ghsax_refsource_MISCWEB
- github.com/pypa/advisory-database/tree/main/vulns/glances/PYSEC-2021-115.yamlghsaWEB
- snyk.io/vuln/SNYK-PYTHON-GLANCES-1311807ghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.