Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐍 PyPI

GHSA-cvwp-r2g2-j824

HIGH

Glances has Incomplete Secrets Redaction: /api/v4/args Endpoint Leaks Password Hash and SNMP Credentials

Also known asCVE-2026-32609
Published
Mar 16, 2026
Updated
Mar 19, 2026
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed

EPSS Exploitation Probability

via FIRST.org ↗
0.5%probability of exploitation in next 30 days
Lower Risk39th percentile+0.42%
0.00%0.33%0.67%1.00%0.1%0.1%0.1%0.5%Apr 26Jun 26Jun 26

EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.

Blast Radius

1 pkg affected
🐍glances

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.

Description

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:

  1. password (line 806-819): When --password is used, this contains the salt + pbkdf2_hmac hash. An attacker can use this for offline brute-force attacks.

  2. snmp_community (line 445): Default "public", but may be set to a secret community string for SNMP monitoring.

  3. snmp_user (line 448): SNMP v3 username, default "private".

  4. snmp_auth (line 450): SNMP v3 authentication key, default "password" but typically set to a secret value.

  5. conf_file (line 198): Path to the configuration file, reveals filesystem structure.

  6. username (line 430/800): The Glances authentication 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 --password (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.

  • 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 glances/password.py:45), which provides some protection but is still crackable with modern hardware.

  • 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)

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐍PyPIglancesall versions4.5.2

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for glances. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.

  2. Fix

    Update glances to 4.5.2 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-cvwp-r2g2-j824 is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

  4. How O3 protects you

    O3 pinpoints whether GHSA-cvwp-r2g2-j824 is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.

Tailored to GHSA-cvwp-r2g2-j824. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.

Frequently Asked Questions

## 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 withou
O3 Security · Impact-Aware SCA

Is GHSA-cvwp-r2g2-j824 in your dependencies?

O3 detects GHSA-cvwp-r2g2-j824 across PyPI dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.