Sep 2, 2026·6 min read·55 visits
NLTK versions prior to 3.10.3 are vulnerable to local arbitrary code execution via an untrusted search path flaw when invoking the Graphviz 'dot' command.
An Untrusted Search Path (CWE-426) vulnerability exists in the Natural Language Toolkit (NLTK) library when executing the Graphviz 'dot' utility. Because the library fails to enforce absolute paths when executing external commands, local attackers can plant a malicious binary named 'dot' inside the current working directory. The library then executes the malicious binary, resulting in local arbitrary code execution under the context of the running Python process.
CVE-2026-78680 is an Untrusted Search Path (CWE-426) vulnerability identified in the Natural Language Toolkit (NLTK) library. This flaw resides in NLTK versions prior to 3.10.3. It allows local attackers to hijack execution flow and run arbitrary code by placing a malicious binary inside the application's current working directory or within a directory listed in a modified PATH environment variable.
The vulnerability is located within two distinct components: dependency graph visualization (nltk.parse.dependencygraph.dot2img) and sentence alignment rendering (nltk.translate.api.AlignedSent._repr_svg_). In both components, the library attempts to run the external Graphviz dot utility to render visual structures. However, it fails to specify absolute paths when spawning the process, causing the host operating system to resolve the executable dynamically.
On systems that search the current working directory first (such as Windows) or systems configured with a relative search path (like . in Unix-like OSs), this behavior allows local arbitrary code execution. The vulnerability is classified under CWE-426 (Untrusted Search Path) and CWE-427 (Use of Uncontrolled Search Path Element), indicating a lack of path enforcement during process execution.
The root cause of CVE-2026-78680 lies in how Python's standard library subprocess module processes bare command arguments on different operating systems. When an application passes a simple string name like "dot" to subprocess.run or subprocess.Popen without providing an absolute path, the underlying system API must resolve the actual file path.
On Windows operating systems, the standard binary search order prioritizes the current working directory (CWD) before looking in system-wide %PATH% directories. Consequently, if an NLTK script is executed in a folder containing an attacker-controlled file named dot.exe, dot.bat, or dot.cmd, the Windows loader executes that local file rather than the legitimate Graphviz binary located in the program files directory.
On Unix-like operating systems, a similar condition occurs if the environment's PATH variable is customized to contain a relative directory entry, such as a dot (.) or empty elements. This dynamic file resolution bypasses security boundaries because NLTK does not verify whether the resolved path points to a trusted directory before executing it.
An inspection of the vulnerable implementation in nltk/parse/dependencygraph.py reveals a critical design flaw in process invocation. Although the code called the validation function find_binary("dot") to locate the binary, the return value was discarded and never assigned to a variable.
# Vulnerable code structure in nltk/parse/dependencygraph.py
def dot2img(dot_string, t="svg"):
try:
find_binary("dot") # Validation result is discarded here
try:
if t in ["dot", "dot_json", "json", "svg"]:
proc = subprocess.run(
["dot", "-T%s" % t], # Bare command name remains
capture_output=True,
input=dot_string,
text=True,
)In the second vulnerable location, nltk/translate/api.py, the visualization method _repr_svg_ did not attempt to perform any path check. It directly executed ["dot", "-T%s" % output_format] using its bare name, allowing process resolution to look up the executable directly from the OS search path.
# Vulnerable code structure in nltk/translate/api.py
def _repr_svg_(self):
dot_string = self._to_dot().encode("utf8")
output_format = "svg"
try:
process = subprocess.Popen(
["dot", "-T%s" % output_format], # Direct bare name invocation
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)To exploit this vulnerability, an attacker must have write access to a directory where a victim executes an NLTK-dependent script, or trick the user into executing NLTK within an untrusted repository. The attacker creates a malicious file named dot (on Unix-like systems) or dot.bat/dot.exe (on Windows) in that workspace directory.
#!/bin/bash
# Malicious 'dot' payload placed in CWD
id > /tmp/compromised
exec /usr/bin/dot "$@"Once the payload is written and marked as executable, the victim runs a script that calls a rendering function like DependencyGraph.dot2img(). When the library triggers the subprocess execution, the operating system executes the local malicious file first. The script executes arbitrary shell commands under the privileges of the victim's Python process, potentially leading to system compromise.
The security impact of CVE-2026-78680 is classified as High. It yields a CVSS v3.1 base score of 7.8, reflecting high impact on confidentiality, integrity, and availability. Because execution occurs under the running Python process context, the exploit obtains the user's local security privileges.
In automated environments, such as continuous integration (CI) pipelines or automated data processing platforms, this vulnerability can facilitate local privilege escalation or container escape if the container process runs with elevated privileges. Similarly, in multi-user environments like Jupyter Notebook hubs, a malicious user could plant a payload to access other users' active work directories.
No mass exploitation has been identified in the wild, placing its EPSS score at 0.0012. However, because NLTK is highly prevalent in machine learning and data science stacks, security teams must proactively scan and remediate this dependency in operational environments.
The vulnerability is resolved in NLTK version 3.10.3. The patch captures the verified, absolute path returned by find_binary("dot") and passes it directly to the subprocess call. This circumvents the operating system's dynamic search path resolution and ensures that only the verified system binary is executed.
# Patched code path
try:
# Resolve to a trusted absolute path; find_binary refuses a
# CWD-relative match, preventing search path hijacking.
dot_binary = find_binary("dot")
except LookupError as e:
raise Exception("Cannot find the dot binary from Graphviz package") from e
try:
proc = subprocess.run(
[dot_binary, "-T%s" % t], # Uses absolute path
# ...
)To verify remediation, execute a script within a directory containing a mock dot executable. In safe versions, NLTK will reject the local relative binary and either throw an exception or execute the legitimate system Graphviz binary. If upgrading is not immediately possible, remove the current directory (.) from the environment's PATH variable and restrict write access to the working directories of automated pipelines.
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
nltk NLTK Project | < 3.10.3 | 3.10.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-426, CWE-427 |
| Attack Vector | Local (L) |
| CVSS v3.1 Score | 7.8 (High) |
| CVSS v4.0 Score | 8.5 (High) |
| EPSS Score | 0.0012 (Percentile: 2.07%) |
| Exploit Maturity | Proof of Concept (PoC) |
| CISA KEV Status | Not Listed |
The application executes an external command with an untrusted or uncontrolled path, allowing attackers to place a malicious executable that hijacks process resolution.
An LDAP injection vulnerability exists in the centraldogma-server-auth-shiro module of LY Corporation Central Dogma before version 0.84.0. The search logic dynamically constructs LDAP search filters by interpolating user-provided usernames without escaping RFC 4515 metacharacters. Unauthenticated remote attackers can leverage this flaw to bypass authentication, enumerate directory hierarchies, and access unauthorized resources.
CVE-2026-11746 is a critical vulnerability in Central Dogma Server prior to version 0.84.0, where an embedded ZooKeeper replication secret silently falls back to a publicly known, hard-coded default string ('ch4n63m3'). Remote attackers with access to the replication network can authenticate as legitimate cluster peers, potentially leading to unauthorized data exposure, state manipulation, or complete cluster takeover.
A logical verification flaw in ZITADEL's external JWT Identity Provider validation allows attackers to bypass session expiration checks. If an incoming JWT lacks the 'exp' claim, the system skips validation entirely, creating an indefinitely valid session. This issue has been addressed in versions 3.4.12 and 4.15.2.
CVE-2026-59149 identifies a directory traversal vulnerability in `@mockoon/commons-server`, the backend mock-server library powering the Mockoon application. The flaw occurs in the path containment validation logic used during raw file response generation. An unauthenticated attacker can exploit this weakness to retrieve arbitrary files from sibling directories sharing a common prefix with the designated static base directory.
An in-depth analysis of CVE-2026-59148, a high-severity flaw in Mockoon where unauthenticated administrative endpoints and a wildcard Cross-Origin Resource Sharing (CORS) policy allow remote execution, state poisoning, and credential theft.
An improper authentication vulnerability (CWE-287) in ZITADEL's external identity provider handler before version 4.15.3 allows remote attackers to perform complete account takeover. When auto-linking by email is enabled, ZITADEL verifies that the local target account has a verified email address but fails to verify if the external provider confirmed ownership of that same email. Attackers can exploit this by registering an unverified account with a victim's email address on a permissive external provider, leading to unauthorized account binding and persistent access.