CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-78680

CVE-2026-78680: Arbitrary Code Execution in NLTK via Untrusted Graphviz Path Resolution

Alon Barad
Alon Barad
Software Engineer

Sep 2, 2026·6 min read·4 visits

Executive Summary (TL;DR)

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.

Vulnerability Overview

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.

Root Cause Analysis

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.

Code Analysis

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,
        )

Exploitation

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.

Impact Assessment

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.

Remediation & Patch Verification

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.

Official Patches

NLTKOfficial fix commit implementing find_binary absolute paths
NLTKGitHub Security Advisory GHSA-6hwm-xvph-95vm

Fix Analysis (2)

Technical Appendix

CVSS Score
7.8/ 10
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
EPSS Probability
0.12%
Top 98% most exploited

Affected Systems

NLTK library installations on WindowsNLTK library installations on Linux/macOS with relative directory entries in PATH

Affected Versions Detail

Product
Affected Versions
Fixed Version
nltk
NLTK Project
< 3.10.33.10.3
AttributeDetail
CWE IDCWE-426, CWE-427
Attack VectorLocal (L)
CVSS v3.1 Score7.8 (High)
CVSS v4.0 Score8.5 (High)
EPSS Score0.0012 (Percentile: 2.07%)
Exploit MaturityProof of Concept (PoC)
CISA KEV StatusNot Listed

MITRE ATT&CK Mapping

T1574.007Path Interception by Search Order Hijacking
Persistence
T1574.008Path Interception by Uncontrolled Search Path Element
Privilege Escalation
CWE-426
Untrusted Search Path

The application executes an external command with an untrusted or uncontrolled path, allowing attackers to place a malicious executable that hijacks process resolution.

Known Exploits & Detection

VulnCheckAnalysis of the search path resolution bug in NLTK Graphviz integration

Vulnerability Timeline

Vulnerability identified and official patch committed
2026-02-15
NLTK version 3.10.3 released containing the security fix
2026-02-15
GitHub Security Advisory GHSA-6hwm-xvph-95vm published
2026-02-15

References & Sources

  • [1]https://github.com/nltk/nltk/security/advisories/GHSA-6hwm-xvph-95vm
  • [2]https://nvd.nist.gov/vuln/detail/CVE-2026-78680
  • [3]https://www.vulncheck.com/advisories/nltk-before-arbitrary-code-execution-via-graphviz-dot-binary

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•27 minutes ago•GHSA-F8FG-PG57-V4J8
5.8

GHSA-f8fg-pg57-v4j8: Sanitizer Filter Bypass via Control Character Injection in league/commonmark

An inconsistency in whitespace handling between the PCRE regex engine, PHP's native trim function, and web browsers allows unauthenticated attackers to bypass XSS protections in the league/commonmark AttributesExtension by injecting a Form Feed (U+000C) control character.

Alon Barad
Alon Barad
0 views•7 min read
•about 1 hour ago•GHSA-JJV6-8J6V-6J52
7.5

GHSA-JJV6-8J6V-6J52: Algorithmic Complexity Denial of Service in league/commonmark

GHSA-JJV6-8J6V-6J52 details multiple algorithmic complexity issues in the SmartPunct and Attributes extensions of the league/commonmark PHP library, leading to high CPU consumption and Denial of Service (DoS) when parsing pathological Markdown inputs.

Amit Schendel
Amit Schendel
4 views•7 min read
•about 3 hours ago•GHSA-8RR7-CVQ3-GMFH
7.5

GHSA-8RR7-CVQ3-GMFH: Algorithmic Complexity Denial of Service in league/commonmark AttributesExtension

An algorithmic complexity vulnerability (CWE-407) in the AttributesExtension of league/commonmark allows unauthenticated remote attackers to cause CPU exhaustion and Denial of Service (DoS) via crafted Markdown payloads containing adjacent or consecutive attributes.

Alon Barad
Alon Barad
3 views•6 min read
•about 4 hours ago•CVE-2026-84371
5.4

CVE-2026-84371: Stored XSS via SVG SMIL URI-list Scheme-Policy Bypass in sanitize-html

A stored Cross-Site Scripting (XSS) vulnerability exists in sanitize-html from version 1.9.0 up to 2.17.6. The flaw permits attackers to bypass scheme-policy enforcement using SVG SMIL animation elements targeting URL attributes with semicolon-separated URI lists.

Alon Barad
Alon Barad
4 views•5 min read
•about 5 hours ago•CVE-2026-84305
5.1

CVE-2026-84305: Algorithmic Complexity Vulnerability (ReindentFilter CPU Exhaustion) in sqlparse

An algorithmic complexity vulnerability in the python sqlparse library versions before 0.6.0 allows an attacker to cause high CPU usage and denial of service via a crafted SQL statement during formatting.

Amit Schendel
Amit Schendel
7 views•6 min read
•about 6 hours ago•CVE-2026-84309
6.9

CVE-2026-84309: Infinite Loop and CPU Exhaustion in pypdf TreeObject.insert_child

An infinite loop vulnerability in pypdf versions prior to 6.16.0 allows attackers to trigger computational resource exhaustion and complete thread locking by supplying a malformed PDF with a cyclic tree structure. When modifying or rewriting document outlines containing circular references, the library endlessly traverses /Next pointers, resulting in application denial of service.

Alon Barad
Alon Barad
6 views•6 min read