Skip to content

Upgrading nltk 2 to 3

Breaking2.0.5 → 3.10.4Breaking1Security258New5Changed9Fixed74Other50

BreakingUpgrade verdict

1 breaking change and 171 security fixes.

  • A helper module for safe imports is gone; use Python's built-in PYTHONSAFEPATH setting instead.
  • NLTK now checks every file and network access it makes, so a malicious corpus or model cannot read or write files outside the trusted data folders or reach internal network addresses.
  • Model files and data formats are now parsed defensively, and slow or pathological input can no longer hang the tokenizers, parsers, stemmers or corpus readers.
  • Output that NLTK produces for terminals, CSV files, the WordNet browser and external tools is now cleaned so it cannot be used to inject commands or markup.
Top 4 of 172 that need code or config changes

Requires Python >=3.10 from 3.9.3 (none stated before).

Adds click, defusedxml, joblib, regex >=2021.8.3, tqdm.

Installs 6 packages in all (was 0).

Breaking1
Removes inisec.py and documents PYTHONSAFEPATH instead.
inisec.pyPYTHONSAFEPATH
Security171
Routes all file paths, archives, downloads, URL fetches and external programs through one sandbox that blocks traversal, symlink escapes, decompression bombs and internal network requests.
Loads pickled models through a restricted unpickler, hardens XML and JSON parsing, and bounds regexes, recursion and slow algorithms against denial-of-service input.
Sanitizes text NLTK writes to the terminal, CSV files, the WordNet browser and third-party tool input against injection.
Gives every pathsec refusal the standard Security Violation marker for spawn_trusted and ZIP audit.
spawn_trusted
Routes downloader, URL loads and CHILDES fetches through pathsec.urlopen, which refuses non-globally-routable addresses and untrusted proxies.
pathsec.urlopennltk.data.loadNLTK_ALLOW_PROXIED_URLOPENnltk.pathsec.ALLOW_PROXIED_FETCHnltk.pathsecnltk.datanltk.data.pathnltk.downloadnltk.downloaderfind()punktstanford_segmenterCorpusReaderARFF_Formatter.writepathsec.ZipFilePackagesave_paramsstaging_tempdirpathsecnltk.parseCCGProver9downloader
Adds size, depth and time bounds so deep trees, relation walks, tgrep, Toolbox and dependency graphs raise ValueError instead of exhausting the stack.
nltk.tree.MAX_TREE_DEPTHnltk.util.MAX_RECURSION_DEPTHchart_parsenltk.parse.chart.DEFAULT_MAX_TIMETree.__repr__nltk.data.loados.systemnltk.xmlsecchomsky_normal_formpathsecpicklesecxmlsec.parse()nltk.xmlsec.parsepathsec.opennltk.tbl.demoskipgramsredos.source_ofredos.rehardenpicklesec.harden_object_graph_fixXMLTree.chomsky_normal_formSyllableTokenizerSeekableUnicodeStreamReader.readlineTreebankWordTokenizerNLTKWordTokenizerstr.splitlinesCoNLLTIMITxmlsecMAX_RECURSION_DEPTHToolboxnltk.data
All compiled regular expressions go through nltk.redos, refusing oversized or deeply nested patterns and timing out matches after nltk.redos.DEFAULT_TIMEOUT (5 seconds).
nltk.redosnltk.redos.errornltk.redos.DEFAULT_TIMEOUTRegexpTokenizerRegexpStemmerRegexpParserre_showTokenSearcher.findallnltk.chatnltk.parsenltk.drawnltk.stemnltk.translatenltk.semnltk.treenltk.tokenizenltk.classifynltk.tagnltk.ccg
Resolves every executed tool binary absolute-only for prover9/mace4, megam, tadm, java, hunpos (CWE-426/427).
prover9mace4megamtadmjavahunposjava()NLTK_ALLOW_UNSAFE_JARSinternals.java()MaltParserfind_filefind_dirGenericStanfordParserStanfordParserO_NOFOLLOW
Sanitizes terminal, CSV, DOT and HTML output so control characters, escape sequences and bidi overrides from corpus text are rendered as visible escapes.
nltk.termsec.safe_printAlignedSentnltk.data.loadWordNetnltk.termsecsanitize_terminaltwitter
Opens gzip file names through pathsec and refuses a linked PanLex Lite database.
pathsecPanLex Litebz2_codecToolboxDatachat80.sql_query
Bounds re_show's caller-supplied regex against ReDoS (CWE-1333).
re_show
Bounds RegexpStemmer's caller-supplied pattern against ReDoS.
RegexpStemmer
NLTK: WekaClassifier passes an unvalidated caller-controlled model path to the weka JVM, bypassing nltk.pathsec containment
nltk.pathsecWekaClassifierpathsecHigh · CVSS 8.6
Hardens the VERSION read in nltk package init with pathsec.open_package_resource.
pathsec.open_package_resource
Hardens stanford tokenizer/segmenter wrappers by validating jar/model paths and argv.
Hardens tagger model loads and tool paths for perceptron, crf, hunpos and stanford taggers.
Stages weka scratch files in a data root and validates the WEKAHOME jar path.
WEKAHOME
Routes corpus-reader scratch tempfiles through a data root and labels framenet path refusals.
Hardens malt and stanford parser wrappers by validating binary/model/IO paths and argv.
Adds remaining GHSA-8mgp security regression tests for pathsec, java, redos, archive and corpus.
Routes top-level nltk regexes through nltk.redos (CWE-1333/CWE-400).
nltk.redos
Routes nltk.sentiment regexes through nltk.redos (CWE-1333/CWE-400).
nltk.sentimentnltk.redos
Routes nltk.corpus regexes through nltk.redos (CWE-1333/CWE-400).
nltk.corpusnltk.redos
Routes nltk.chunk regexes through nltk.redos (CWE-1333/CWE-400).
nltk.chunknltk.redos
Routes nltk.app regexes through nltk.redos (CWE-1333/CWE-400).
nltk.appnltk.redos
Bounds compile-time DoS (ValueError) in the concordance and nemo GUI regex handlers (CWE-1333/CWE-400).
concordancenemo
Hardens RegexpStemmer against pre-compiled ReDoS patterns (CWE-1333).
RegexpStemmer
Guards model-artifact loaders against un-sandboxed open().
Stages REPP scratch input in an nltk.data root instead of the shared system temp directory.
nltk.dataREPP
Refuses NUL bytes in pathsec.validate_path and adds a pathsec attack-candidate harness.
pathsec.validate_path
Re-checks the normalized form of a no-protocol resource path against traversal (CWE-22).
Extends the no-unsandboxed-open guard to app/draw/twitter and routes every open through pathsec.open.
pathsec.open
Opens operator-chosen app/twitter paths with an annotated builtin open instead of pathsec.open.
pathsec.open
Hardens and completes the CoreNLP server-option allowlist (CWE-88/22/502).
Hardens CoreNLPServer start attempts.
CoreNLPServer
Extends the no-unsandboxed-open guard to gzip, bz2, lzma, zipfile and tempfile, with a coverage test.
gzipbz2lzmazipfiletempfile
Adds a GHSA-j456 live probe and expands the GHSA-8mgp probe attack set.
Extends the tool model-file guards to crf, stanford tagger and segmenter.
crfstanford taggersegmenter
Guard the Stanford tagger and segmenter input against line injection.
StanfordTaggerStanfordSegmenter
Guard the maxent parameter files against outside-root paths and unrepresentable names.
Maxent
Routes every module's file removal, rename, privacy test and sqlite open through pathsec.
pathsec
Creates perceptron model files exclusively under the pinned directory (issue 3980).
Sandboxes Stanford JAR execution to nltk_data directories.
Hardens the path-traversal and file-I/O sandbox, closing a write-side symlink TOCTOU and shared-temp squat (CWE-22/59/377).
Extends algorithmic-complexity DoS hardening with a repo-wide sweep and two-string distances (CWE-407/CWE-400).
Bounds unbounded-work DoS in parsers and grammar transforms (CWE-407/674/835).
Sandboxes MaltParser's Java execution (CVE-2026-12252, CVE-2026-12841).
MaltParser
Trusts the system temp dir only when it is private (CWE-377/CWE-378).
Validates corpus-reader roots against the data sandbox (CWE-73).
Validates per-call java() options and replaces the -XX:/-D allowlist with a minimal one (CWE-88).
java()
Adds further security hardening (CWE-407, CWE-426, CWE-427, CWE-502, CWE-59, CWE-776, CWE-918).
NLTK versions before 3.10.3 contain a path sandbox bypass vulnerability in corpus-reader constructors that allows attackers to read files outside the intended data root. Attackers can supply arbitrary corpus root paths to LinThesaurusCorpusReader and PanLexLiteCorpusReader constructors to access filesystem content and SQLite databases outside the pathsec sandbox boundary.
NLTK AllowlistUnpickler dotted-name validation bypass allows remote code execution
High · CVSS 8.8
NLTK: Uncontrolled search path when invoking the Graphviz 'dot' binary
High · CVSS 7.8
NLTK before 3.10.3 contains a server-side request forgery vulnerability in nltk.pathsec.urlopen (and callers nltk.data.load, nltk.downloader.Downloader.index/download) when an HTTP proxy is configured. pathsec.urlopen validates the requested hostname locally, but proxy-handler inheritance disables the safe HTTP/HTTPS handlers so the actual fetch is performed by the proxy against a destination that is never re-validated. An attacker can supply a validated public URL that the proxy forwards to an internal loopback-only service, allowing disclosure of internal HTTP resources, loading of forged downloader indexes, and installation of attacker-chosen package content.
NLTK through 3.10.3 contains a path traversal vulnerability in model-artifact APIs that bypass pathsec enforcement by using raw file operations on caller-controlled paths. Attackers can read or write files outside allowed sandbox roots through TransitionParser, AveragedPerceptron, PerceptronTagger, and maxent parameter APIs when pathsec is enabled.
NLTK before 3.10.3 contains a regular expression denial of service vulnerability in Pl196xCorpusReader that allows attackers to cause quadratic CPU consumption by supplying malformed TEI blocks with many unmatched opening tags. Attackers can exploit lazy regex patterns in the read_block method through public APIs like words() and tagged_words() to force repeated rescans and achieve near-quadratic runtime growth.
NLTK versions before 3.10.3 use xml.etree.ElementTree to parse XML in multiple modules, which honors entity declarations in document DTDs. Attackers can craft XML payloads with nested entity declarations that expand from hundreds of bytes to megabytes in memory, causing denial of service.
NLTK 3.9.4 through 3.10.2 contains a path traversal vulnerability in CrubadanCorpusReader. _load_lang_ngrams joins the corpus root with crubadan_code, the column-0 value read from the corpus table.txt mapping file, and opens the result with the builtin open() rather than the pathsec-validated opener, so os.path.join discards the root when that value is absolute and the read escapes the corpus directory without the containment check nltk.pathsec applies when ENFORCE is set. An attacker who controls a corpus package can disclose file contents outside the corpus root through lang_freq, limited to paths ending in -3grams.txt whose contents parse as token count lines.
Low · CVSS 3.3
NLTK before 3.10.3 contains an uncontrolled recursion vulnerability in nltk.featstruct.FeatStructReader that allows unauthenticated attackers to cause a denial of service by supplying deeply nested feature-structure input. Attackers can craft trivial payloads with nested brackets that exceed Python's recursion limit and raise an unhandled RecursionError, crashing applications that parse user-supplied feature structures or feature grammars.
NLTK versions before 3.10.3 contain a filesystem containment bypass vulnerability in the Downloader.download and Downloader.incr_download methods that allows attackers to overwrite files outside the install root through pre-existing hardlinks. Attackers with write access to a shared downloader directory can create hardlinks pointing to outside-root files that are then overwritten during normal package extraction, mutating files outside the intended install tree.
NLTK before 3.10.3 fails to validate JVM options passed through the per-call options parameter in the java() function, allowing attackers to inject dangerous JVM flags. Attackers can supply malicious options like -agentpath, -javaagent, or @argfile to Stanford wrapper classes to achieve arbitrary code execution.
NLTK versions before 3.10.3 contain a path traversal vulnerability in corpus readers that reopen root-derived paths using built-in open() instead of nltk.pathsec.open(), allowing symlinks to escape trusted roots. Attackers who stage symlinked corpus files under a trusted data root can disclose outside-root content through normal corpus reader methods like channels(), domains(), and synonyms().
NLTK: Quadratic CPU Exhaustion in XMLCorpusView._read_xml_fragment()
Low · CVSS 3.7
NLTK before 3.10.3 contains a regular expression denial of service (ReDoS) vulnerability in the tgrep module. The _tgrep_node_action function compiles user-supplied regular expressions embedded in /regex/ pattern nodes and executes them via re.search against tree node labels without any validation or timeout. An attacker who controls the tgrep pattern (e.g., via tgrep_positions() or tgrep_compile() exposed to external input) can supply a pattern that triggers catastrophic backtracking, causing indefinite CPU saturation that blocks the Python process.
nltk PorterStemmer in versions <= 3.10.2 (fixed in 3.10.3) contains an inefficient-algorithmic-complexity denial of service in PorterStemmer.stem(). The _is_consonant() helper walks backward over the entire run of trailing 'y' characters on every call, and _measure() invokes it for each stem position, causing O(n^2) behavior. A single ~20-50 KB untrusted token consisting of a long run of the letter 'y' followed by a matching suffix (e.g., 'ness') can pin a CPU core for seconds to minutes, causing availability impact.
NLTK versions before 3.10.3 contain a remote code execution vulnerability in allowlisted pickle loaders that trust entire module namespaces instead of specific safe callables. Attackers can craft malicious pickle payloads invoking dangerous in-namespace functions like ReppTokenizer._execute and numpy.f2py.crackfortran.myeval through pickle REDUCE to execute arbitrary commands during model or tokenizer artifact loading.
NLTK: Uncontrolled resource consumption in RecursiveDescentParser via ambiguous or left-recursive grammars
Fixes a symlink escape in FramenetCorpusReader (CWE-59).
FramenetCorpusReader
Guards tempfile.gettempdir() when building pathsec allowed roots.
tempfile.gettempdir()
nltk versions before 3.10.2 contain a symlink-based arbitrary file read vulnerability in IPIPANCorpusReader methods that bypass nltk.pathsec validation entirely. Attackers can place a symlink in the corpus root directory and read arbitrary files accessible to the process by calling channels(), domains(), categories(), or fileids() methods with the symlink filename.
NLTK versions before 3.10.2 contain a symlink-based sandbox bypass in FramenetCorpusReader that allows attackers to read arbitrary XML files outside the corpus root. Attackers can place symlinks with names containing no path separators inside the corpus subdirectory, which pass the path validation guard and are resolved to files outside the intended corpus root when accessed via frame_by_name(), _lu_file(), or doc() methods.
NLTK TweetTokenizer vulnerable to denial of service through catastrophic regex backtracking
High · CVSS 7.5
Blocks XML entity expansion (XXE) in the downloader.
Prevents DNS-rebinding SSRF in pathsec.urlopen.
pathsec.urlopen
NLTK (Natural Language Toolkit) is a suite of open source Python modules, data sets, and tutorials supporting research and development in Natural Language Processing. Prior to 3.10.0-rc1, nltk.data.load() in NLTK is vulnerable to path traversal via URL-encoded path separators and traversal segments when using the nltk: URL scheme. The unsafe-path regex check is performed before url2pathname() decodes the %xx sequences (a classic decode-after-check / TOCTOU-style flaw), allowing an attacker to bypass the protection documented in NLTK's SECURITY.md and read arbitrary files from the filesystem. While literal traversal strings such as ../../../etc/passwd are correctly blocked, encoded variants such as %2fetc%2fpasswd, %2e%2e%2f..., and ..%2f..%2f slip past the regex and are subsequently decoded into a real filesystem path. This vulnerability is fixed in 3.10.0-rc1.
High · CVSS 7.5
Blocks path traversal in NKJPCorpusReader.
NKJPCorpusReader
Blocks path traversal in FramenetCorpusReader.frame().
FramenetCorpusReader.frame()
Natural Language Toolkit (NLTK): ReDoS in NLTK ReviewsCorpusReader FEATURES regex
ReviewsCorpusReaderFEATURESHigh · CVSS 7.5
Fixes remaining corpus reader pathsec gaps before ENFORCE=True RC.
ENFORCE
Replaces unsafe exec() with importlib in the utility CLI.
exec()importlib
Prevents ReDoS in TextTilingTokenizer paragraph-break regex (CWE-1333).
TextTilingTokenizer
Prevents ReDoS in SensevalCorpusReader _fixXML (CWE-400).
SensevalCorpusReader_fixXML
Resolves relative MaltParser dir via MALT_PARSER, not the CWD (CWE-426).
MALT_PARSER
Bounds LogicParser recursion depth to prevent uncaught RecursionError (CWE-674).
LogicParser
Resolves relative ReppTokenizer dir via REPP_TOKENIZER, not the CWD (CWE-427).
ReppTokenizerREPP_TOKENIZER
Does not load weka.jar from the CWD (CWE-494).
weka.jar
Stops running the senna binary from the current working directory (CWE-829).
senna
Prevents ReDoS in chunk tag-pattern parsing (CWE-1333).
Routes _download_package() writes through pathsec.open.
_download_package()pathsec.open
Resolves symlinks in the downloader containment check (CWE-59).
Uses defusedxml in corpus readers to block XML entity-expansion DoS (CWE-776).
defusedxml
Stops exponential ReDoS in XMLCorpusView _VALID_XML_RE (CWE-1333).
XMLCorpusView_VALID_XML_RE
Routes read_sents through the pathsec sentinel.
read_sents
Stops running the candc/boxer binary from the current working directory (CWE-426).
candcboxer
Fixes algorithmic-complexity DoS in DependencyGraph.contains_cycle.
DependencyGraph.contains_cycle
Bounds recursion in PorterStemmer._is_consonant (CWE-674).
PorterStemmer._is_consonant
Closes validate/extract path mismatch in the pathsec Zip-Slip guard (CWE-22).
pathsec
Validates the path in GzipFileSystemPathPointer.open() (CWE-22).
GzipFileSystemPathPointer.open()
Requires a session token for WordNet Browser shutdown (CWE-352).
WordNet Browser
Removes a quadratic scan in VADER polarity_scores (CWE-407).
polarity_scores
Bounds a super-linear n-gram scan in RIBES word_rank_alignment (CWE-407).
word_rank_alignment
Routes custom_distance through the pathsec sentinel (CWE-22).
custom_distance
Stops quadratic ReDoS in CCG lexicon parsing (CWE-1333).
Rejects CWD-relative binaries in find_binary (CWE-426).
find_binary
Reads XML corpora through the path-pointer sentinel to fix a path traversal issue (CWE-22).
Caps zip decompression to prevent decompression-bomb denial of service (CWE-409).
Stops symlink-following arbitrary deletion in Downloader stale-cleanup (CWE-59).
Downloader
Makes Alignment index sparse to stop an unbounded-allocation denial of service (CVE-2026-12837).
Alignment
Makes ConfusionMatrix sparse to stop a quadratic-memory denial of service (CVE-2026-12839).
ConfusionMatrix
Bounds Model.satisfy quantifier-nesting cost to stop a combinatorial denial of service (CVE-2026-12840).
Model.satisfy
Bounds the everygrams default max_len to stop an unbounded-allocation denial of service (CVE-2026-12861).
everygrams
Routes DependencyGraph.load through the pathsec sandbox (CVE-2026-12867).
DependencyGraph.load
Makes the Cistem stemmer linear to stop a quadratic-time denial of service (CVE-2026-12868).
Cistem
Routes data.retrieve writes through the pathsec sandbox (CVE-2026-12871).
data.retrieve
Bounds DRT resolve_anaphora work to stop a quadratic time and memory denial of service (CVE-2026-12873).
resolve_anaphora
Bounds chart parse-tree extraction to stop an exponential denial of service (CVE-2026-12886).
Makes the valuation separator regex linear to stop a quadratic ReDoS (CVE-2026-12890).
Makes the feature-structure rename regex linear to stop a quadratic ReDoS (CVE-2026-12919).
Blocks IPv6 transition-embedded internal IPv4 addresses in the SSRF filter to close a NAT64 bypass (CWE-918).
Bounds generate() derivation-expansion steps to stop an unbounded-enumeration denial of service (CVE-2026-12864).
generate()
Bounds the phrase_extraction default max_phrase_length to stop a cubic denial of service (CVE-2026-12870).
phrase_extractionmax_phrase_length
Prevents arbitrary file write via XML attribute injection in nltk.downloader.
nltk.downloader
Makes jaro_similarity flagged-position lookup O(1) to stop a cubic-time DoS (CVE-2026-12926).
jaro_similarity
Bounds NgramCounter distinct-ngram count to stop an unbounded-memory DoS (CVE-2026-12928).
NgramCounter
Makes METEOR word matching linear to stop a quadratic-time DoS (CVE-2026-12929).
METEOR
Bounds theorem-prover proof search to stop an unbounded-search DoS (CWE-400 / CWE-674).
Guards CHILDESCorpusReader.convert_age against malformed input (CWE-476).
CHILDESCorpusReader.convert_age
Validates CoNLL and CMUdict reader lines to stop malformed-line crashes (CWE-20).
Fixes a quadratic-time DoS in NLTK LEPOR alignment.
LEPOR
Fixes a DoS in NLTK PropBank.
PropBank
Fixes a denial of service via quadratic complexity in NLTK segmentation metrics.
Fixes a quadratic-time DoS in NLTK Tree.un_chomsky_normal_form.
Tree.un_chomsky_normal_form
Fixes a quadratic ReDoS in NLTK Text.findall token search.
Text.findall
Fixes an exponential beta-reduction DoS in NLTK Expression.simplify.
Expression.simplify
Fixes a quadratic-memory DoS in NLTK ProjectiveDependencyParser.
ProjectiveDependencyParser
Fixes a DoS in NLTK NomBank instance parsing.
NomBank
Fixes a DoS in the NLTK segmentation pk metric via an uncaught divide-by-zero.
Fixes a quadratic-backtracking ReDoS in NLTK AlpinoCorpusReader._normalize.
AlpinoCorpusReader._normalize
Fixes a quadratic-time DoS in NLTK Markdown corpus reader blockquotes and lists.
Fixes a quadratic-time DoS in NLTK GDFA.
GDFA
Fixes CWE-88 JVM argument injection in java_options (CVE-2026-12841).
java_options
Fixes MaltParser process-wide CWD pollution during parsing (CVE-2026-12614).
MaltParser
NLTK before 3.10.0 (affected versions <=3.9.4) contains an unsafe pickle deserialization vulnerability in the TransitionParser.parse() method (nltk/parse/transitionparser.py). The method calls pickle_load() with the default restricted=False, routing deserialization through WarningUnpickler, which does not override find_class() and therefore permits arbitrary class resolution. When an application loads an attacker-crafted model file, embedded pickle gadget chains execute arbitrary Python code with the privileges of the user running the application. NLTK provides a RestrictedUnpickler for safe deserialization, but it is not used by production code paths. Fixed in 3.10.0.
TransitionParser
Cleans Stanford Java wrapper temp files and isolates Java options (CVE-2026-12615).
Enforces restrictive primitive type checking in pathsec wrappers.
NLTK before 3.10.0 (affected versions <= 3.9.4) contains a server-side request forgery (SSRF) vulnerability in the validate_network_url() function in nltk/pathsec.py. The _resolve_hostname() helper catches OSError and ValueError during socket.getaddrinfo() and returns an empty list; when DNS resolution fails, the validation loop executes no IP checks and the function fails open, allowing urlopen() to proceed without validation. An attacker who can trigger DNS resolution failures or use DNS rebinding can bypass SSRF protections and reach restricted network resources, including cloud metadata endpoints (e.g., 169.254.169.254).
NLTK versions before 3.10.0 contain a path traversal vulnerability in FramenetCorpusReader and NKJPCorpusReader that allows attackers to parse XML files outside the corpus root by supplying unsafe selectors or poisoned index state. Attackers can exploit frame_by_name, doc, lu, and header methods with crafted parameters to read arbitrary XML files accessible to the application.
High · CVSS 7.5
Natural Language Toolkit (NLTK): Path Traversal in NKJPCorpusReader leads to Arbitrary File Read and bypasses the nltk.pathsec sandbox (ENFORCE=True)
High · CVSS 7.5
NLTK versions before 3.10.0 contain a logic bug in FileSystemPathPointer.open() where the sandbox validation check compares a normalized path against itself, making the security check permanently inert. Attackers can pass file:// URLs to nltk.data.load() to read arbitrary files accessible to the process user, including credentials and configuration files.
A vulnerability in nltk.downloader in nltk/nltk versions <= 3.9.4 allows for cross-package resource and model poisoning. The downloader extracts package archives into shared namespaces such as corpora/ and taggers/ instead of package-isolated roots, and validates package integrity only after the archive has been written and extracted. This design flaw enables one package to overwrite another package's trusted resources within the same namespace, making the changes immediately active through ordinary NLTK APIs. This issue persists across fresh interpreter restarts and can affect downstream workflows, including machine learning pipelines and reproducibility-sensitive environments.
Medium · CVSS 6.5
NLTK versions before 3.10.0 default to ENFORCE=False in pathsec.py, causing all security validation functions to emit warnings instead of raising exceptions. Attackers can bypass path traversal and pickle deserialization protections by exploiting the disabled security controls that are only active when manually enabled.
Natural Language Toolkit (NLTK): DNS-rebinding SSRF filter bypass in nltk.pathsec.urlopen (nltk.download / nltk.data.load) defeats ENFORCE mode
High · CVSS 8.6
NLTK before 3.10.0 contains an arbitrary local file read vulnerability in StreamBackedCorpusView that bypasses pathsec.ENFORCE by calling builtins.open() directly instead of pathsec.open(). Attackers who control the fileid argument can read arbitrary local files regardless of the ENFORCE setting, including sensitive system files and application credentials.
NLTK versions before 3.10.0 contain a regular expression denial of service vulnerability in Text.findall() and TokenSearcher.findall() methods that accept user-supplied regular expressions without validation or timeout. Attackers can supply crafted regex patterns that cause catastrophic backtracking, resulting in indefinite CPU saturation and denial of service to all users of the Python process.
Natural Language Toolkit (NLTK) has path traversal in FramenetCorpusReader.frame() that allows arbitrary XML file read, bypassing the nltk.pathsec sandbox (ENFORCE=True)
High · CVSS 7.5
NLTK (Natural Language Toolkit) is a suite of open source Python modules, data sets, and tutorials supporting research and development in Natural Language Processing. In versions 3.9.3 and prior, the NLTK downloader does not validate the subdir and id attributes when processing remote XML index files. Attackers can control a remote XML index server to provide malicious values containing path traversal sequences (such as ../), which can lead to arbitrary directory creation, arbitrary file creation, and arbitrary file overwrite. Commit 89fe2ec2c6bae6e2e7a46dad65cc34231976ed8a patches the issue.
High · CVSS 8.1
In nltk/nltk versions 3.9.3 and earlier, five Stanford interface classes (StanfordPOSTagger, StanfordNERTagger, StanfordParser, StanfordDependencyParser, and StanfordNeuralDependencyParser) are vulnerable to untrusted JAR code execution. These classes accept user-controllable JAR paths and execute them via the java() function, which invokes subprocess.Popen() without integrity verification. This vulnerability is identical to CVE-2026-0848, which was fixed for StanfordSegmenter by adding SHA256 verification. However, the fix was not applied to these additional classes, leaving them susceptible to arbitrary code execution when loading untrusted JAR files.
High · CVSS 7.8
NLTK (Natural Language Toolkit) is a suite of open source Python modules, data sets, and tutorials supporting research and development in Natural Language Processing. In versions 3.9.3 and prior, nltk.app.wordnet_app contains a reflected cross-site scripting issue in the lookup_... route. A crafted lookup_<payload> URL can inject arbitrary HTML/JavaScript into the response page because attacker-controlled word data is reflected into HTML without escaping. This impacts users running the local WordNet Browser server and can lead to script execution in the browser origin of that application. Commit 1c3f799607eeb088cab2491dcf806ae83c29ad8f fixes the issue.
Medium · CVSS 6.1
NLTK (Natural Language Toolkit) is a suite of open source Python modules, data sets, and tutorials supporting research and development in Natural Language Processing. In versions 3.9.3 and prior, nltk.app.wordnet_app allows unauthenticated remote shutdown of the local WordNet Browser HTTP server when it is started in its default mode. A simple GET /SHUTDOWN%20THE%20SERVER request causes the process to terminate immediately via os._exit(0), resulting in a denial of service. Commit bbaae83db86a0f49e00f5b0db44a7254c268de9b patches the issue.
High · CVSS 7.5
NLTK versions before 3.9.4 contain a symlink escape vulnerability in CorpusReader.open() that allows local attackers to read arbitrary files outside the corpus root. The vulnerability exists because path validation is lexical and does not account for symlink resolution, enabling attackers to place symlinks inside the corpus root to access files outside the intended boundary.
NLTK versions before 3.9.4 contain an unbounded recursion vulnerability in JSONTaggedDecoder.decode_obj() that allows attackers to cause denial of service by supplying deeply nested JSON structures. Attackers can craft JSON payloads exceeding the recursion limit to trigger an unhandled RecursionError that crashes the Python process.
A vulnerability in NLTK versions up to and including 3.9.2 allows arbitrary file read via path traversal in multiple CorpusReader classes, including WordListCorpusReader, TaggedCorpusReader, and BracketParseCorpusReader. These classes fail to properly sanitize or validate file paths, enabling attackers to traverse directories and access sensitive files on the server. This issue is particularly critical in scenarios where user-controlled file inputs are processed, such as in machine learning APIs, chatbots, or NLP pipelines. Exploitation of this vulnerability can lead to unauthorized access to sensitive files, including system files, SSH private keys, and API tokens, and may potentially escalate to remote code execution when combined with other vulnerabilities.
High · CVSS 7.5
A critical vulnerability exists in the NLTK downloader component of nltk/nltk, affecting all versions. The _unzip_iter function in nltk/downloader.py uses zipfile.extractall() without performing path validation or security checks. This allows attackers to craft malicious zip packages that, when downloaded and extracted by NLTK, can execute arbitrary code. The vulnerability arises because NLTK assumes all downloaded packages are trusted and extracts them without validation. If a malicious package contains Python files, such as __init__.py, these files are executed automatically upon import, leading to remote code execution. This issue can result in full system compromise, including file system access, network access, and potential persistence mechanisms.
Critical · CVSS 10.0
NLTK versions <=3.9.2 are vulnerable to arbitrary code execution due to improper input validation in the StanfordSegmenter module. The module dynamically loads external Java .jar files without verification or sandboxing. An attacker can supply or replace the JAR file, enabling the execution of arbitrary Java bytecode at import time. This vulnerability can be exploited through methods such as model poisoning, MITM attacks, or dependency poisoning, leading to remote code execution. The issue arises from the direct execution of the JAR file via subprocess with unvalidated classpath input, allowing malicious classes to execute when loaded by the JVM.
Critical · CVSS 10.0
NLTK (Natural Language Toolkit) before version 3.9.3 contains an eval injection vulnerability in the nltk.collocations module that allows an attacker who controls command-line arguments to execute arbitrary Python code. When collocations.py is invoked directly, the __main__ block passes command-line arguments directly to eval() as suffixes of BigramAssocMeasures without allowlist validation or sanitization, enabling an attacker to supply a Python expression that escapes the intended attribute lookup and executes arbitrary code including OS commands via the os module.
NLTK through 3.8.1 allows remote code execution if untrusted packages have pickled Python code, and the integrated data package download functionality is used. This affects, for example, averaged_perceptron_tagger and punkt.
nltk is vulnerable to Inefficient Regular Expression Complexity
NLTK (Natural Language Toolkit) is a suite of open source Python modules, data sets, and tutorials supporting research and development in Natural Language Processing. Versions prior to 3.6.5 are vulnerable to regular expression denial of service (ReDoS) attacks. The vulnerability is present in PunktSentenceTokenizer, sent_tokenize and word_tokenize. Any users of this class, or these two functions, are vulnerable to the ReDoS attack. In short, a specifically crafted long input to any of these vulnerable functions will cause them to take a significant amount of execution time. If your program relies on any of the vulnerable functions for tokenizing unpredictable user input, then we would strongly recommend upgrading to a version of NLTK without the vulnerability. For users unable to upgrade the execution time can be bounded by limiting the maximum length of an input to any of the vulnerable functions. Our recommendation is to implement such a limit.
nltk is vulnerable to Inefficient Regular Expression Complexity
NLTK Downloader before 3.4.5 is vulnerable to a directory traversal, allowing attackers to write arbitrary files via a ../ (dot dot slash) in an NLTK package (ZIP archive) that is mishandled during extraction.