PT-2026-25847 · Pypi · Glance
Published
2026-03-16
·
Updated
2026-03-16
·
CVE-2026-32609
CVSS v3.1
7.5
| Vector | AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N |
Summary
The GHSA-gh4x fix (commit 5d3de60) addressed unauthenticated configuration secrets exposure on the
/api/v4/config endpoints by introducing as dict secure() redaction. However, the /api/v4/args and /api/v4/args/{item} endpoints were not addressed by this fix. These endpoints return the complete command-line arguments namespace via vars(self.args), which includes the password hash (salt + pbkdf2 hmac), SNMP community strings, SNMP authentication keys, and the configuration file path. When Glances runs without --password (the default), these endpoints are accessible without any authentication.Details
The secrets exposure fix (GHSA-gh4x, commit 5d3de60) modified three config-related endpoints to use
as dict secure() when no password is configured:# glances/outputs/glances restful api.py:1168 (FIXED) args json = self.config.as dict() if self.args.password else self.config.as dict secure()
However, the
api args and api args item endpoints were not part of this fix and still return all arguments without any sanitization:# glances/outputs/glances restful api.py:1222-1237 def api args(self): try: # Get the RAW value of the args dict # Use vars to convert namespace to dict args json = vars(self.args) except Exception as e: raise HTTPException(status.HTTP 404 NOT FOUND, f"Cannot get args ({str(e)})") return GlancesJSONResponse(args json)
And the item-specific endpoint:
# glances/outputs/glances restful api.py:1239-1258 def api args item(self, item: str): ... args json = vars(self.args)[item] return GlancesJSONResponse(args json)
The
self.args namespace contains sensitive fields set during initialization in glances/main.py:-
(line 806-819): Whenpassword
is used, this contains the salt + pbkdf2 hmac hash. An attacker can use this for offline brute-force attacks.--password -
(line 445): Defaultsnmp community
, but may be set to a secret community string for SNMP monitoring."public" -
(line 448): SNMP v3 username, defaultsnmp user
."private" -
(line 450): SNMP v3 authentication key, defaultsnmp auth
but typically set to a secret value."password" -
(line 198): Path to the configuration file, reveals filesystem structure.conf file -
(line 430/800): The Glances authentication username.username
Both endpoints are registered on the authenticated router (line 504-505):
f'{base path}/args': self. api args, f'{base path}/args/{{item}}': self. api args item,
When
--password is not set (the default), the router has NO authentication dependency (line 479-480), making these endpoints completely unauthenticated:if self.args.password: router = APIRouter(prefix=self.url prefix, dependencies=[Depends(self.authentication)]) else: router = APIRouter(prefix=self.url prefix)
PoC
Scenario 1: No password configured (default deployment)
# Start Glances in web server mode (default, no password) glances -w # Access all command line arguments without authentication curl -s http://localhost:61208/api/4/args | python -m json.tool # Expected output includes sensitive fields: # "password": "", # "snmp community": "public", # "snmp user": "private", # "snmp auth": "password", # "username": "glances", # "conf file": "/home/user/.config/glances/glances.conf", # Access specific sensitive argument curl -s http://localhost:61208/api/4/args/snmp community curl -s http://localhost:61208/api/4/args/snmp auth
Scenario 2: Password configured (authenticated deployment)
# Start Glances with password authentication glances -w --password --username admin # Authenticate and access args (password hash exposed to authenticated users) curl -s -u admin:mypassword http://localhost:61208/api/4/args/password # Returns the salt$pbkdf2 hmac hash which enables offline brute-force
Impact
-
Unauthenticated network reconnaissance: When Glances runs without
(the common default for internal/trusted networks), anyone who can reach the web server can enumerate SNMP credentials, usernames, file paths, and all runtime configuration.--password -
Offline password cracking: When authentication is enabled, an authenticated user can retrieve the password hash (salt + pbkdf2 hmac) and perform offline brute-force attacks. The hash uses pbkdf2 hmac with SHA-256 and 100,000 iterations (see
), which provides some protection but is still crackable with modern hardware.glances/password.py:45 -
Lateral movement: Exposed SNMP community strings and v3 authentication keys can be used to access other network devices monitored by the Glances instance.
-
Supply chain for CORS attack: Combined with the default CORS misconfiguration (finding 001), these secrets can be stolen cross-origin by a malicious website.
Recommended Fix
Apply the same redaction pattern used for the
/api/v4/config endpoints:# glances/outputs/glances restful api.py SENSITIVE ARGS = frozenset({ 'password', 'snmp community', 'snmp user', 'snmp auth', 'conf file', 'password prompt', 'username used', }) def api args(self): try: args json = vars(self.args).copy() if not self.args.password: for key in SENSITIVE ARGS: if key in args json: args json[key] = "********" # Never expose the password hash, even to authenticated users if 'password' in args json and args json['password']: args json['password'] = "********" except Exception as e: raise HTTPException(status.HTTP 404 NOT FOUND, f"Cannot get args ({str(e)})") return GlancesJSONResponse(args json) def api args item(self, item: str): if item not in self.args: raise HTTPException(status.HTTP 400 BAD REQUEST, f"Unknown argument item {item}") try: if item in SENSITIVE ARGS: if not self.args.password: return GlancesJSONResponse("********") if item == 'password': return GlancesJSONResponse("********") args json = vars(self.args)[item] except Exception as e: raise HTTPException(status.HTTP 404 NOT FOUND, f"Cannot get args item ({str(e)})") return GlancesJSONResponse(args json)
Fix
Information Disclosure
Found an issue in the description? Have something to add? Feel free to write us 👾
Weakness Enumeration
Related Identifiers
Affected Products
Glance