# NLTK: pathsec SSRF protection can be bypassed when a proxy is configured

NLTK's pathsec SSRF guard validates hostnames but skips its pinned safe handlers when a proxy is configured, letting proxied fetches reach internal loopback services.

- Payout: Research
- Severity: high
- Program: NLTK
- Found by: sondt99
- Disclosed: 2026-09-08
- CVE: CVE-2026-78682
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-6ww7-3frv-cqxh
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-6ww7-3frv-cqxh
- Tags: area:oss domain:oss impact:integrity impact:internal-access kind:research platform:ghsa sev:high tech:python technique:incomplete-fix technique:source-review vuln:ssrf

**Target:** nltk.pathsec.urlopen / nltk.data.load / Downloader index and download fetches
**Root cause:** Proxy-handler inheritance disables _SafeHTTPHandler/_SafeHTTPSHandler, so the validated hostname no longer matches the actual egress destination; the proxied branch copies ProxyHandler from the global opener and skips the pinned handlers.
**Steps:**
1. Start a loopback-only HTTP server serving 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; observe internal response returned.
4. Instantiate `Downloader(server_index_url=...)`, call `index()` and `download()`; observe internal-only content parsed and installed.
**How found:** Noticed the hardened direct path pins the validated numeric destination IP before opening the socket, while the proxied branch copies ProxyHandler instances from the global opener, marks the request proxied, and skips the pinned handlers — so validated hostname diverges from actual egress. Confirmed across urlopen, data.load, Downloader.index and Downloader.download.
**Exploitation:** With an HTTP proxy configured, a caller trusting pathsec as an SSRF barrier fetches a validated public URL; the proxy resolves/forwards it to an internal loopback service, returning internal secrets, forged downloader indexes, and attacker-chosen ZIP package content that NLTK installs.
**Escalation:** Chained from SSRF read into downloader index forgery and arbitrary package installation via Downloader.download().
**Insight:** When a library pins egress by IP to defeat DNS rebinding, check every alternate transport branch (proxy handlers, redirects, connection reuse) for a path that skips the pinned handler; a proxy makes the validated hostname irrelevant to the real destination.

