CVE-2026-12259: NLTK Missing Post-Download Integrity Verification Allows Vulnerability

MODERATE
Advisory Identifier: GHSA-5wp5-5229-5g6q
CVSS 5.3
CWE-494
Published
Advisory Summary

CVE-2026-12259 is a MODERATE (CVSS 5.3) missing post-download integrity verification allows vulnerability (CWE-494: Download of Code Without Integrity Check) affecting NLTK libraries in the PyPI ecosystem. The issue involves missing post-download integrity verification allows malicious package injection. Remediation is available by upgrading affected packages to version 3.9.3.

CVE-2026-12259 at a Glance

CVE Identifier CVE-2026-12259
GHSA Identifier GHSA-5wp5-5229-5g6q
Severity MODERATE
CVSS v3.1 Base Score 5.3
CWE Classification CWE-494: Download of Code Without Integrity Check
Affected Product NLTK
Package Ecosystem PyPI
Published Date
Last Updated

Security Impact

CVSS: 5.3

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N).

Attack Vector Network (AV:N)
Attack Complexity High (AC:H)
Privileges Required None (PR:N)
User Interaction Required (UI:R)
Scope Unchanged (S:U)
Confidentiality None (C:N)
Integrity High (I:H)
Availability None (A:N)

How to Fix CVE-2026-12259

To remediate this vulnerability, upgrade all affected NLTK dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

nltk fixed: 3.9.3
pip install nltk>=3.9.3
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

pip show nltk

How to Check if You Are Affected

To determine whether your Python environment is affected by CVE-2026-12259, inspect your installed packages using pip:

pip show nltk

Analyze the terminal output to locate any version of NLTK in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 3.9.3), your application is affected.

Note: The pip show nltk command checks currently installed packages in your active Python environment.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-494: Download of Code Without Integrity Check, where the product downloads source code or an executable from a remote location and executes the code without sufficiently verifying the origin and integrity of the code. In NLTK, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

NLTK's package downloader in nltk/downloader.py does not verify file integrity after download and before extraction. The download flow at lines 789-825: 1. File is downloaded to a temp path via HTTP 2. os.replace(tmp_filepath, filepath) moves it to the final location (line 799) 3. Extraction begins via _unzip_iter() (line 825) Between steps 2 and 3, there is no SHA-256 verification. The checksum logic exists in _pkg_status() (lines 982-1015) but it is only used BEFORE download as a status check ("is this package already installed and up-to-date?"). It is never called after download to verify the file that was actually received. Attack vectors: 1. MITM during HTTP download (NLTK downloads from http:// by default on some mirrors) 2. Race condition on shared filesystems (attacker replaces file between os.replace and _unzip_iter) 3. DNS poisoning redirecting to attacker-controlled server PoC: ```python import nltk import unittest.mock import zipfile import io import os # Create a malicious zip that will be "downloaded" malicious_zip = io.BytesIO() with zipfile.ZipFile(malicious_zip, 'w') as zf: zf.writestr('punkt_tab/tokenizers/punkt_tab/english.pickle', b'MALICIOUS PAYLOAD - attacker controlled content') # Patch urllib to return our malicious zip with unittest.mock.patch('urllib.request.urlopen') as mock_urlopen: mock_response = unittest.mock.MagicMock() mock_response.read.return_value = malicious_zip.getvalue() mock_response.headers = {'Content-Length': str(len(malicious_zip.getvalue()))} mock_urlopen.return_value = mock_response # Download proceeds, no integrity check catches the swap # nltk.download('punkt_tab') # Would install attacker payload ``` This is distinct from CVE-2024-39705 (pickle deserialization via download) and CVE-2025-14009 (zip-slip path traversal). Those address what happens AFTER extraction. This finding addresses the gap BEFORE extraction where integrity is never verified. Suggested fix: After os.replace() and before _unzip_iter(), compute SHA-256 of the final file and compare against the expected checksum from the package index. Reject and delete the file if the hash does not match.

CVE-2026-12259 Affected NLTK Versions

1 component(s)
Fixed Versions:
3.9.3
Product / Package Ecosystem Affected Versions Fixed Version
nltk
PyPI
< 3.9.3
3.9.3

References

Frequently Asked Questions

What is CVE-2026-12259?
CVE-2026-12259 is a security vulnerability in NLTK involving Missing Post-Download Integrity Verification Allows Malicious Package Injection under CWE-494: Download of Code Without Integrity Check.
Which NLTK versions are affected?
Affected versions include releases prior to 3.9.3 across affected packages: nltk.
What version fixes CVE-2026-12259?
Upgrading to 3.9.3 (or the latest patched release for your respective branch) resolves the vulnerability.
Is nltk affected?
Yes, nltk is affected in releases prior to 3.9.3. Upgrade your dependency to 3.9.3 or later.
What is the CVSS score of CVE-2026-12259?
CVE-2026-12259 has a CVSS v3.1 base score of 5.3 (MODERATE) with vector string CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N.
What CWE is associated with CVE-2026-12259?
CVE-2026-12259 is classified under CWE-494: Download of Code Without Integrity Check (The product downloads source code or an executable from a remote location and executes the code without sufficiently verifying the origin and integrity of the code.).
How can I check PyPI dependencies for CVE-2026-12259?
Run the dependency tree command: 'pip show nltk'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-5wp5-5229-5g6q",
  "modified" : "2026-09-08T15:27:55Z",
  "published" : "2026-09-08T15:27:55Z",
  "aliases" : [ "CVE-2026-12259" ],
  "summary" : "NLTK: Missing Post-Download Integrity Verification Allows Malicious Package Injection",
  "details" : "NLTK's package downloader in nltk/downloader.py does not verify file integrity after download and before extraction.\n\nThe download flow at lines 789-825:\n1. File is downloaded to a temp path via HTTP\n2. os.replace(tmp_filepath, filepath) moves it to the final location (line 799)\n3. Extraction begins via _unzip_iter() (line 825)\n\nBetween steps 2 and 3, there is no SHA-256 verification. The checksum logic exists in _pkg_status() (lines 982-1015) but it is only used BEFORE download as a status check (\"is this package already installed and up-to-date?\"). It is never called after download to verify the file that was actually received.\n\nAttack vectors:\n1. MITM during HTTP download (NLTK downloads from http:// by default on some mirrors)\n2. Race condition on shared filesystems (attacker replaces file between os.replace and _unzip_iter)\n3. DNS poisoning redirecting to attacker-controlled server\n\nPoC:\n```python\nimport nltk\nimport unittest.mock\nimport zipfile\nimport io\nimport os\n\n# Create a malicious zip that will be \"downloaded\"\nmalicious_zip = io.BytesIO()\nwith zipfile.ZipFile(malicious_zip, 'w') as zf:\n    zf.writestr('punkt_tab/tokenizers/punkt_tab/english.pickle', \n                b'MALICIOUS PAYLOAD - attacker controlled content')\n\n# Patch urllib to return our malicious zip\nwith unittest.mock.patch('urllib.request.urlopen') as mock_urlopen:\n    mock_response = unittest.mock.MagicMock()\n    mock_response.read.return_value = malicious_zip.getvalue()\n    mock_response.headers = {'Content-Length': str(len(malicious_zip.getvalue()))}\n    mock_urlopen.return_value = mock_response\n    \n    # Download proceeds, no integrity check catches the swap\n    # nltk.download('punkt_tab')  # Would install attacker payload\n```\n\nThis is distinct from CVE-2024-39705 (pickle deserialization via download) and CVE-2025-14009 (zip-slip path traversal). Those address what happens AFTER extraction. This finding addresses the gap BEFORE extraction where integrity is never verified.\n\nSuggested fix: After os.replace() and before _unzip_iter(), compute SHA-256 of the final file and compare against the expected checksum from the package index. Reject and delete the file if the hash does not match.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "PyPI",
      "name" : "nltk"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "3.9.3"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 3.9.2"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/nltk/nltk/security/advisories/GHSA-5wp5-5229-5g6q"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-12259"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/nltk/nltk/pull/3449"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/nltk/nltk/commit/0e26734a61094b628d93e26dc18dd7302567ac46"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/nltk/nltk"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/nltk/nltk/releases/tag/3.9.3"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/pypa/advisory-database/tree/main/vulns/nltk/PYSEC-2026-3729.yaml"
  }, {
    "type" : "WEB",
    "url" : "https://huntr.com/bounties/659ccf6d-12d4-4d4a-84c0-078633c35a5d"
  }, {
    "type" : "WEB",
    "url" : "https://www.vulncheck.com/advisories/nltk-before-missing-post-download-integrity-verification"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-494" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-09-08T15:27:55Z",
    "nvd_published_at" : null
  }
}