{"id":"PYSEC-2026-3868","summary":"NLTK: Uncontrolled search path when invoking the Graphviz 'dot' binary","details":"Two NLTK sites executed the Graphviz `dot` program by bare name, so process creation resolved it via the search path — and on Windows via the current working directory — rather than a validated absolute location. An attacker who can place a file named `dot` where resolution looks (the CWD on Windows, or a writable/relative entry such as `.` on `PATH`) has their binary executed in place of Graphviz (arbitrary code execution).\n\nAffected (\u003c= 3.10.2):\n- `nltk.parse.dependencygraph.dot2img` — called `find_binary(\"dot\")` but discarded the returned validated path and then ran the bare name `[\"dot\", ...]`, so the validation had no effect.\n- `nltk.translate.api.AlignedSent._repr_svg_` — ran the bare name with no validation at all (IPython SVG rendering).\n\nThis is the same class already fixed for the senna, weka, boxer, malt, repp and hunpos wrappers. `nltk.internals.find_binary` refuses a CWD-relative match for a bare tool name and returns only a trusted absolute path; the fix runs that path in both sites.\n\n---\n\n## Attack demonstration\nCaptured output, not illustrative. A `./dot` that writes a `PWNED` marker, planted in the CWD with `.` prepended to `PATH`.\n\n**The vulnerable behaviour (old bare-name exec):**\n```\nControl (OLD behavior) — bare ['dot'] in this dir with '.' on PATH:\n  bare ['dot'] executed planted binary = True\n```\n\n**The patched functions refuse it:**\n```\nFIXED code, with ./dot planted and '.' on PATH:\n  dependencygraph.dot2img : Exception \"Cannot find the dot binary...\"  | planted-binary-executed=False  safe\n  AlignedSent._repr_svg_  : Exception \"Cannot find the dot binary...\"  | planted-binary-executed=False  safe\n```\n\n**And `find_binary` itself was attacked directly** (the fix trusts nothing else):\n```\nAttack 1: ./dot in CWD, no dot on PATH            -\u003e LookupError (refused)  safe\nAttack 2: ./dot/dot (dir 'dot' holding 'dot')     -\u003e LookupError (refused)  safe\nAttack 3: '.' on PATH + ./dot                     -\u003e LookupError (refused)  safe\nAttack 4: attacker-writable ABSOLUTE dir on PATH  -\u003e returned /…/evilbin/dot (absolute)\n```\nAttack 4 is out of scope: trusting an absolute directory that is already on `PATH` is the operating system's own trust model — an attacker who can write to a `PATH` directory owns the account regardless of NLTK. `find_binary` defends specifically against the CWD/relative injection that bare-name exec is vulnerable to (attacks 1–3), which is exactly what this fix inherits.\n\nEnvironment: python 3.13.7. `dot` is not required to reproduce — the planted binary is the payload.","aliases":["CVE-2026-78680","GHSA-6hwm-xvph-95vm"],"modified":"2026-09-10T12:15:07.211785746Z","published":"2026-09-10T09:44:59.053936Z","references":[{"type":"WEB","url":"https://github.com/nltk/nltk/security/advisories/GHSA-6hwm-xvph-95vm"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-78680"},{"type":"WEB","url":"https://github.com/nltk/nltk/commit/1a3cd1764ab3deb084fb66d0ffb4873717659538"},{"type":"PACKAGE","url":"https://github.com/nltk/nltk"},{"type":"WEB","url":"https://github.com/nltk/nltk/releases/tag/v3.10.3"},{"type":"WEB","url":"https://www.vulncheck.com/advisories/nltk-before-arbitrary-code-execution-via-graphviz-dot-binary"},{"type":"PACKAGE","url":"https://pypi.org/project/nltk"},{"type":"ADVISORY","url":"https://github.com/advisories/GHSA-6hwm-xvph-95vm"}],"affected":[{"package":{"name":"nltk","ecosystem":"PyPI","purl":"pkg:pypi/nltk"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"3.10.3"}]}],"versions":["0.8","0.9","0.9.3","0.9.4","0.9.5","0.9.6","0.9.7","0.9.8","0.9.9","2.0.1","2.0.1rc1","2.0.1rc2-git","2.0.1rc3","2.0.1rc4","2.0.2","2.0.3","2.0.4","2.0.5","2.0b4","2.0b5","2.0b6","2.0b7","2.0b8","2.0b9","3.0.0","3.0.0b1","3.0.0b2","3.0.1","3.0.2","3.0.3","3.0.4","3.0.5","3.1","3.10.0","3.10.1","3.10.2","3.2","3.2.1","3.2.2","3.2.3","3.2.4","3.2.5","3.3","3.4","3.4.1","3.4.2","3.4.3","3.4.4","3.4.5","3.5","3.5b1","3.6","3.6.1","3.6.2","3.6.3","3.6.4","3.6.5","3.6.6","3.6.7","3.7","3.8","3.8.1","3.9","3.9.1","3.9.2","3.9.3","3.9.4","3.9b1"],"database_specific":{"source":"https://github.com/pypa/advisory-database/blob/main/vulns/nltk/PYSEC-2026-3868.yaml"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"},{"type":"CVSS_V4","score":"CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N"}]}