GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration

GHSA-P3M8-78J2-G5P3

Vulnerability from github – Published: 2026-09-02 15:40 – Updated: 2026-09-02 15:40
VLAI
Summary
NLTK: Default ENFORCE=False Disables All pathsec Security Controls
Details

NLTK's pathsec.py security module defaults to ENFORCE=False (line 24), which means all 8 security validation functions only emit RuntimeWarning instead of raising exceptions when violations are detected.

The pathsec module was introduced as the fix for CVE-2024-39705 (arbitrary code execution via pickle) and CVE-2026-0846 (path traversal). However, with ENFORCE=False as the default:

  1. pathsec.open('/etc/passwd') succeeds (reads the file, emits warning)
  2. pathsec.validate_network_url('http://169.254.169.254/...') succeeds (warning only)
  3. pickle.loads() via nltk.data.load() proceeds despite unsafe source (warning only)

Every security gate follows the same pattern:

ENFORCE = os.environ.get('NLTK_PATHSEC_ENFORCE', '').lower() in ('1', 'true', 'yes')

def validate_something(path):
    if is_violation(path):
        if ENFORCE:
            raise SecurityError('...')  # Only raised when env var is set
        else:
            warnings.warn('...', RuntimeWarning)  # Default: warning only
    # Execution continues regardless

This means the security remediations for CVE-2024-39705 and CVE-2026-0846 are effectively disabled by default. Any user who installed NLTK 3.9.x expecting the security fixes to be active is still vulnerable unless they manually set NLTK_PATHSEC_ENFORCE=1.

PoC:

import nltk.pathsec
import warnings

# Show that ENFORCE is False by default
print(f'ENFORCE = {nltk.pathsec.ENFORCE}')  # False

# Attempt to read /etc/passwd through pathsec -- should be blocked
with warnings.catch_warnings(record=True) as w:
    warnings.simplefilter('always')
    result = nltk.pathsec.open('/etc/passwd', 'r')
    print(f'File opened: {result.name}')  # /etc/passwd
    print(f'Warning emitted: {w[0].message}')  # RuntimeWarning (not an exception)
    # Attack succeeds -- file is readable

The correct default is fail-secure: ENFORCE should be True unless explicitly disabled. The current default makes the security module opt-in rather than opt-out, defeating its purpose.

Suggested fix: Change default to ENFORCE=True. Users who need backwards compatibility can set NLTK_PATHSEC_ENFORCE=0 to explicitly disable.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 3.9.4"
      },
      "package": {
        "ecosystem": "PyPI",
        "name": "nltk"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "3.10.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-62388"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1188"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-09-02T15:40:33Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "NLTK\u0027s pathsec.py security module defaults to ENFORCE=False (line 24), which means all 8 security validation functions only emit RuntimeWarning instead of raising exceptions when violations are detected.\n\nThe pathsec module was introduced as the fix for CVE-2024-39705 (arbitrary code execution via pickle) and CVE-2026-0846 (path traversal). However, with ENFORCE=False as the default:\n\n1. pathsec.open(\u0027/etc/passwd\u0027) succeeds (reads the file, emits warning)\n2. pathsec.validate_network_url(\u0027http://169.254.169.254/...\u0027) succeeds (warning only)\n3. pickle.loads() via nltk.data.load() proceeds despite unsafe source (warning only)\n\nEvery security gate follows the same pattern:\n```python\nENFORCE = os.environ.get(\u0027NLTK_PATHSEC_ENFORCE\u0027, \u0027\u0027).lower() in (\u00271\u0027, \u0027true\u0027, \u0027yes\u0027)\n\ndef validate_something(path):\n    if is_violation(path):\n        if ENFORCE:\n            raise SecurityError(\u0027...\u0027)  # Only raised when env var is set\n        else:\n            warnings.warn(\u0027...\u0027, RuntimeWarning)  # Default: warning only\n    # Execution continues regardless\n```\n\nThis means the security remediations for CVE-2024-39705 and CVE-2026-0846 are effectively disabled by default. Any user who installed NLTK 3.9.x expecting the security fixes to be active is still vulnerable unless they manually set NLTK_PATHSEC_ENFORCE=1.\n\nPoC:\n```python\nimport nltk.pathsec\nimport warnings\n\n# Show that ENFORCE is False by default\nprint(f\u0027ENFORCE = {nltk.pathsec.ENFORCE}\u0027)  # False\n\n# Attempt to read /etc/passwd through pathsec -- should be blocked\nwith warnings.catch_warnings(record=True) as w:\n    warnings.simplefilter(\u0027always\u0027)\n    result = nltk.pathsec.open(\u0027/etc/passwd\u0027, \u0027r\u0027)\n    print(f\u0027File opened: {result.name}\u0027)  # /etc/passwd\n    print(f\u0027Warning emitted: {w[0].message}\u0027)  # RuntimeWarning (not an exception)\n    # Attack succeeds -- file is readable\n```\n\nThe correct default is fail-secure: ENFORCE should be True unless explicitly disabled. The current default makes the security module opt-in rather than opt-out, defeating its purpose.\n\nSuggested fix: Change default to ENFORCE=True. Users who need backwards compatibility can set NLTK_PATHSEC_ENFORCE=0 to explicitly disable.",
  "id": "GHSA-p3m8-78j2-g5p3",
  "modified": "2026-09-02T15:40:33Z",
  "published": "2026-09-02T15:40:33Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/nltk/nltk/security/advisories/GHSA-p3m8-78j2-g5p3"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-62388"
    },
    {
      "type": "WEB",
      "url": "https://github.com/nltk/nltk/pull/3593"
    },
    {
      "type": "WEB",
      "url": "https://github.com/nltk/nltk/commit/155e40343cff0bf50d233e274a12e04d1428b1d9"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/nltk/nltk"
    },
    {
      "type": "WEB",
      "url": "https://github.com/nltk/nltk/releases/tag/v3.10.0"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pypa/advisory-database/tree/main/vulns/nltk/PYSEC-2026-3722.yaml"
    },
    {
      "type": "WEB",
      "url": "https://www.vulncheck.com/advisories/nltk-before-insecure-default-configuration-pathsec"
    }
  ],
  "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": "NLTK: Default ENFORCE=False Disables All pathsec Security Controls"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

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…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…