CVE-2026-78682: NLTK: SSRF bypass via proxy-handler downgrade
GHSA-6ww7-3frv-cqxh HIGH PoC AVAILABLE CISA: TRACK*NLTK's pathsec module validates hostnames before fetching URLs, but when an HTTP proxy is configured, the library silently routes the request through the proxy's handlers instead of the pinned, validated socket path — letting a proxied request reach internal-only services or forge a downloader index while the validated hostname check reports success. The blast radius looks contained on paper (2 tracked downstream dependents, EPSS 0.00253, no CISA KEV listing, no public exploit or Nuclei template), but nltk is a foundational NLP dependency embedded deep in text-preprocessing and RAG-adjacent pipelines, and any environment that enforces an egress proxy — common in regulated enterprises — is exactly the setup this bug reactivates. Exploitation requires an adversary with influence over the proxy path (compromised corporate proxy, malicious insider, or an SSRF chained from another service), which raises the bar from trivial but does not eliminate real risk in proxy-mandated networks. Patch to nltk 3.10.3, which fails closed on proxied fetches by default; until then, do not set `NLTK_ALLOW_PROXIED_URLOPEN=1` and audit any service that calls `nltk.data.load()` or `Downloader.download()` from inside a proxied network for unexpected corpus/index sources.
What is the risk?
High severity per the advisory but tempered by real-world exploitability constraints: the attacker needs some control over or visibility into the victim's outbound proxy path, not just network reachability to the target service. There is no CISA KEV listing, no public exploit code, and no Nuclei template, and EPSS scores this at 0.00253 (a low absolute exploitation probability). However, the affected code paths (`pathsec.urlopen`, `nltk.data.load`, `Downloader.index`/`download`) are core to how nltk fetches remote corpora and packages, so any deployment relying on nltk's SSRF protections while running behind a corporate/CI proxy is exposed until patched. Package risk score is reported as 0/100 and downstream dependents as only 2, suggesting limited direct blast radius today, but nltk's ubiquity in NLP tooling means indirect exposure (via other packages bundling it) is likely undercounted.
How does the attack unfold?
What systems are affected?
| Package | Ecosystem | Vulnerable Range | Patched |
|---|---|---|---|
| Cline | pip | <= 3.10.2 | 3.10.3 |
Do you use Cline? You're affected.
How severe is it?
What should I do?
1 step-
1) Upgrade to nltk 3.10.3 or later, which fails closed on proxied fetches under
ENFORCEand requires explicit opt-in (NLTK_ALLOW_PROXIED_URLOPEN=1ornltk.pathsec.ALLOW_PROXIED_FETCH=True) to restore proxied behavior. 2) If you cannot upgrade immediately, avoid running nltk data-fetching code (nltk.data.load,Downloader.index/download) in any environment withhttp_proxy/https_proxyset, or block those variables for the process. 3) Only enable the opt-in flag if you fully trust your proxy's egress control and have validated it cannot be pointed at internal-only hosts. 4) Detection: audit environment variables in containers/CI runners that invoke nltk downloads for proxy configuration, monitor proxy logs for nltk-driven requests resolving to loopback/internal ranges, and alert on unexpected corpus checksums or ZIP contents fromnltk_datainstalls.
What does CISA's SSVC say?
Source: CISA Vulnrichment (SSVC v2.0). Decision based on the CISA Coordinator decision tree.
How is it classified?
Which compliance frameworks are affected?
This CVE is relevant to:
Frequently Asked Questions
What is CVE-2026-78682?
NLTK's pathsec module validates hostnames before fetching URLs, but when an HTTP proxy is configured, the library silently routes the request through the proxy's handlers instead of the pinned, validated socket path — letting a proxied request reach internal-only services or forge a downloader index while the validated hostname check reports success. The blast radius looks contained on paper (2 tracked downstream dependents, EPSS 0.00253, no CISA KEV listing, no public exploit or Nuclei template), but nltk is a foundational NLP dependency embedded deep in text-preprocessing and RAG-adjacent pipelines, and any environment that enforces an egress proxy — common in regulated enterprises — is exactly the setup this bug reactivates. Exploitation requires an adversary with influence over the proxy path (compromised corporate proxy, malicious insider, or an SSRF chained from another service), which raises the bar from trivial but does not eliminate real risk in proxy-mandated networks. Patch to nltk 3.10.3, which fails closed on proxied fetches by default; until then, do not set `NLTK_ALLOW_PROXIED_URLOPEN=1` and audit any service that calls `nltk.data.load()` or `Downloader.download()` from inside a proxied network for unexpected corpus/index sources.
Is CVE-2026-78682 actively exploited?
Proof-of-concept exploit code is publicly available for CVE-2026-78682, increasing the risk of exploitation.
How to fix CVE-2026-78682?
1) Upgrade to nltk 3.10.3 or later, which fails closed on proxied fetches under `ENFORCE` and requires explicit opt-in (`NLTK_ALLOW_PROXIED_URLOPEN=1` or `nltk.pathsec.ALLOW_PROXIED_FETCH=True`) to restore proxied behavior. 2) If you cannot upgrade immediately, avoid running nltk data-fetching code (`nltk.data.load`, `Downloader.index`/`download`) in any environment with `http_proxy`/`https_proxy` set, or block those variables for the process. 3) Only enable the opt-in flag if you fully trust your proxy's egress control and have validated it cannot be pointed at internal-only hosts. 4) Detection: audit environment variables in containers/CI runners that invoke nltk downloads for proxy configuration, monitor proxy logs for nltk-driven requests resolving to loopback/internal ranges, and alert on unexpected corpus checksums or ZIP contents from `nltk_data` installs.
What systems are affected by CVE-2026-78682?
This vulnerability affects the following AI/ML architecture patterns: training pipelines, RAG pipelines, agent frameworks.
What is the CVSS score for CVE-2026-78682?
No CVSS score has been assigned yet.
What is the AI security impact?
Affected AI Architectures
MITRE ATLAS Techniques
AML.T0010.002 Data AML.T0025 Exfiltration via Cyber Means Compliance Controls Affected
What are the technical details?
Original Advisory
### Summary Current NLTK source reopens SSRF in proxied environments. `pathsec.urlopen()` validates the requested hostname locally, but once proxy inheritance is enabled the real fetch is performed by the proxy rather than by the validated direct-connect socket path. ### Details - **Vulnerability type:** Server-side request forgery - **Affected component:** `nltk.pathsec.urlopen`, `nltk.data.load`, `nltk.downloader.Downloader.index`, `nltk.downloader.Downloader.download` - **Affected versions:** Current source `v3.10.0-rc2`; published `3.9.4` was a negative control and did not reproduce. - **Patched versions:** Not yet patched - **Root cause:** Proxy-handler inheritance disables `_SafeHTTPHandler` and `_SafeHTTPSHandler`, so the validated hostname no longer matches the actual egress destination. The hardened direct path pins the validated numeric destination IP before opening the socket. The proxied branch instead copies `ProxyHandler` instances from the global opener, marks the request as proxied, and skips the pinned handlers. I confirmed that a validated public URL can be fetched from a loopback-only internal service through the proxy path via `pathsec.urlopen()`, `nltk.data.load()`, `Downloader.index()`, and `Downloader.download()`. ### PoC **Preconditions** - The runtime has an HTTP proxy configured and the caller relies on `pathsec` to keep network fetches SSRF-safe. **Steps** 1. Start a loopback-only HTTP server that serves secret text, a valid downloader index, and a ZIP payload. 2. Configure a proxy that forwards a validated public URL to that internal loopback service. 3. Call `pathsec.urlopen()` or `nltk.data.load()` on the public URL and observe the internal response is returned. 4. Instantiate `Downloader(server_index_url=...)`, call `index()` and `download()`, and observe internal-only content is parsed and installed. **Minimal reproducible excerpt** ```text {'urlopen': 'PROXY_TEXT_SECRET', 'data_load': 'PROXY_TEXT_SECRET', 'downloaded_file': 'INTERNAL_ZIP_SECRET'} ``` ### Impact Consumers that trust `pathsec` as an SSRF barrier in proxied environments can be made to read internal-only HTTP resources, load forged downloader indexes, and install attacker-chosen package content fetched from the proxy's network view. ### Remediation Preserve destination validation for the actual proxy egress target or fail closed when the request would otherwise downgrade into an unpinned proxied path. Add regression tests across `pathsec.urlopen`, `nltk.data.load`, and downloader fetches with a configured proxy. ### References - https://github.com/nltk/nltk/blob/v3.10.0-rc2/nltk/pathsec.py#L468-L518 - https://github.com/nltk/nltk/blob/v3.10.0-rc2/nltk/data.py#L1247-L1283 - https://github.com/nltk/nltk/blob/v3.10.0-rc2/nltk/downloader.py#L875-L889 - https://github.com/nltk/nltk/blob/v3.10.0-rc2/nltk/downloader.py#L1220-L1226 - https://github.com/nltk/nltk/blob/3.9.4/nltk/pathsec.py#L245-L250 --- ## Fix + attack demonstration (verified) NLTK cannot pin the egress through a proxy, so it stops pretending to: under `ENFORCE` a proxied fetch is **refused** rather than performed unvalidated. Operators who trust their proxy opt back in with `NLTK_ALLOW_PROXIED_URLOPEN=1` or `nltk.pathsec.ALLOW_PROXIED_FETCH=True`; under `ENFORCE=False` the refusal degrades to a warning. This closes the **whole class** (environment proxies and explicit `ProxyHandler` alike), because NLTK declines any fetch whose egress it cannot validate. ## Attack demonstration (reproduced; captured output) A loopback HTTP server stands in for the internal target; `http_proxy` points at it; NLTK is asked for a **public** IP URL. **Before the fix** — the internal secret is exfiltrated through the proxy: ``` validate_network_url(public): PASSED *** BYPASS: pathsec.urlopen returned INTERNAL content via proxy: 'INTERNAL_ONLY_SECRET' ``` **After the fix** — five scenarios, isolated subprocesses: | Scenario | Result | |---|---| | proxied (env) + ENFORCE | `PermissionError` — **blocked** | | proxied + opt-in | returns secret — escape hatch works | | explicit `ProxyHandler` (not env) + ENFORCE | `PermissionError` — **blocked** (whole class) | | no proxy (direct) | internal IP still refused — pinning intact | | proxied + `ENFORCE=False` | returns secret **+ warns** | ## Tests `nltk/test/unit/test_pathsec.py`: 64 passed. Added an end-to-end regression (`test_proxied_fetch_does_not_reach_internal_target`) plus `test_env_proxy_fails_closed_under_enforce`; the prior `test_env_proxy_skips_pinning_handlers` (which encoded the vulnerable path) is re-expressed as the opt-in case. Existing direct-path DNS-rebinding and IP-policy tests unchanged and passing. pre-commit (isort/black/ruff) clean. ## Note The upfront `validate_network_url()` and the direct-path IP pinning (from the earlier DNS-rebinding fixes, CVE-2026-54296 / GHSA-qvv7) are unchanged — this only closes the proxied downgrade they didn't cover.
Exploitation Scenario
An AI/NLP service runs inside a corporate network that enforces an outbound HTTP proxy for compliance/egress-control reasons. An attacker who has compromised that proxy (or is an insider with proxy access) configures it to redirect a validated, public-looking download URL to an internal loopback service instead. When the nltk-based service calls `Downloader.download()` to fetch a 'trusted' corpus or model resource, the proxy transparently substitutes internal content: a forged downloader index pointing to attacker-controlled ZIP files. Because nltk's `_SafeHTTPHandler`/`_SafeHTTPSHandler` pinning is silently bypassed once proxy inheritance kicks in, the service installs and later loads the attacker's ZIP as if it were the legitimate resource — enabling either exfiltration of internal-only data (secrets served by the loopback host) or a supply-chain-style substitution of trusted linguistic data with attacker-controlled content.
Weaknesses (CWE)
CWE-441 Unintended Proxy or Intermediary ('Confused Deputy')
Primary
CWE-918 Server-Side Request Forgery (SSRF)
Primary
CWE-441 — Unintended Proxy or Intermediary ('Confused Deputy'): The product receives a request, message, or directive from an upstream component, but the product does not sufficiently preserve the original source of the request before forwarding the request to an external actor that is outside of the product's control sphere. This causes the product to appear to be the source of the request, leading it to act as a proxy or other intermediary between the upstream component and the external actor.
- [Architecture and Design] Enforce the use of strong mutual authentication mechanism between the two parties.
- [Architecture and Design] Whenever a product is an intermediary or proxy for transactions between two other components, the proxy core should not drop the identity of the initiator of the transaction. The immutability of the identity of the initiator must be maintained and should be forwarded all the way to the target.
Source: MITRE CWE corpus.
References
- github.com/advisories/GHSA-6ww7-3frv-cqxh
- github.com/nltk/nltk/commit/767333a005a1cd3d82d2029215f2dbe66a5844d9
- github.com/nltk/nltk/releases/tag/v3.10.3
- github.com/nltk/nltk/security/advisories/GHSA-6ww7-3frv-cqxh
- github.com/pypa/advisory-database/tree/main/vulns/nltk/PYSEC-2026-3733.yaml
- nvd.nist.gov/vuln/detail/CVE-2026-78682
- vulncheck.com/advisories/nltk-before-ssrf-protection-bypass-via-proxy
Timeline
Related Vulnerabilities
CVE-2026-44211 9.6 cline: WebSocket auth bypass enables terminal RCE
Same package: cline CVE-2026-59723 8.8 Cline: missing Origin check on Hub enables RCE
Same package: cline CVE-2026-76845 6.5 adm-zip: arbitrary file overwrite via symlink extraction
Same package: cline GHSA-wx3m-whqv-xv47 skillctl: path traversal enables credential exfiltration
Same package: cline CVE-2026-88009 Traefik: HTTP routing desync enables auth/log bypass
Same package: cline