VYPR
Moderate severityNVD Advisory· Published Jul 29, 2021· Updated Sep 16, 2024

XML External Entity (XXE) Injection

CVE-2021-23418

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.

PackageAffected versionsPatched versions
GlancesPyPI
< 3.2.13.2.1

Affected products

2

Patches

3
9d6051be4a42

Security audit - B411 #1025

https://github.com/nicolargo/glancesnicolargoJul 9, 2021via ghsa
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()]})
     
    
4b87e979afdc

Add NEWS file and improve Makefile

https://github.com/nicolargo/glancesnicolargoJun 12, 2021via ghsa
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
    
85d5a6b4af31

Security audit - B411 #1025

https://github.com/nicolargo/glancesnicolargoApr 24, 2021via ghsa
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

News mentions

0

No linked articles in our index yet.