medium

CVE-2026-68520

PyPI · glances

Summary

Glances: as_dict_secure() Value-Level Bypass Leaks Credentials in URL Values via /api/4/config

Severity
medium
CVSS
5.3
EPSS
0.4% (p35)
CWE
CWE-200
Also known as
GHSA-4h34-v6r8-mmjc
Published
2026-08-17
Updated
2026-08-17

Advisory details

Summary

Glances provides as_dict_secure() explicitly designed for unauthenticated API access, with a docstring stating it returns "a sanitised copy of the configuration dict" where "Sensitive keys in remaining sections are replaced by '********'". However, the implementation only checks KEY names against a regex pattern and never inspects VALUE content. The documented [ip] config section supports public_api (URL), public_username (login), and public_password (password). While public_password is correctly masked, both public_api (when containing embedded credentials like https://user:pass@host/) and public_username are returned in full to unauthenticated users via GET /api/4/config.

Affected Versions

Glances latest (Docker: nicolargo/glances:latest)

Root Cause

In glances/config.py, as_dict_secure():

_SECURE_SENSITIVE_KEY_RE = re.compile(r"password|token|secret|api_key|apikey|ssl_keyfile", re.IGNORECASE)

def as_dict_secure(self):
    """Return a sanitised copy of the configuration dict.
    Intended for unauthenticated API access.
    - Sensitive keys in remaining sections are replaced by '********'.
    """
    sanitized = {}
    for section, options in self.as_dict().items():
        if section in _SECURE_BLOCKED_SECTIONS: continue
        sanitized[section] = {
            key: "********" if _SECURE_SENSITIVE_KEY_RE.search(key) else value
            for key, value in options.items()
        }
    return sanitized

In glances/outputs/glances_restful_api.py:

# Line 1294
args_json = self.config.as_dict() if self.args.password else self.config.as_dict_secure()

The [ip] config section documents: public_api (URL), public_username (login), public_password (password).

Impact

Prerequisites

Environment

Reproduction Steps

docker run -d --name glances-test -p 8080:61208 -e GLANCES_OPT='-w' nicolargo/glances:latest
sleep 20
docker exec glances-test sed -i 's|public_api=https://ipv4.ipleak.net/json/|public_api=https://admin:secret123@ipv4.ipleak.net/json/|' /etc/glances/glances.conf
docker exec glances-test sed -i 's|#public_username=<myname>|public_username=myname|' /etc/glances/glances.conf
docker exec glances-test sed -i 's|#public_password=<mysecret>|public_password=mysecret|' /etc/glances/glances.conf
docker restart glances-test
sleep 15
curl -s "$TARGET/api/4/config/ip"
# Returns: {"public_api": "https://admin:secret123@...", "public_username": "myname", "public_password": "********"}

Evidence

See C:/Tools/glances-config-leak-evidence.txt.

Dedup Check

Suggested Remediation

Add "username" and "login" to sensitive key pattern, and check values for embedded credentials in URLs.

Disclosure Timeline

Reporter

GitHub username: Todor

References

Related advisories

Is your project exposed to this? Stateward checks every dependency on every pull request and flags it only if your code actually reaches it.

Check my repo

Summarize with AI

ChatGPTClaudePerplexity

Sources: CISA KEV (public domain), OSV.dev & GitHub Advisory Database (CC-BY-4.0), FIRST EPSS, NVD/CWE (public domain). Served live from the Stateward advisory database.