CSIRTS // UNIFIED SECURITY ADVISORY FEEDSYS ● ONLINE · POWERED BY INTELFUSIONS.COM

GHSA-6hm5-jgcp-p838: Natural Language Toolkit (NLTK): Path Traversal in NKJPCorpusReader leads to Arbitrary File Read and bypasses the nltk.pathsec sandbox (ENFORCE=True)

highCVSS 7.5CVE-2026-12072
Summary A path-traversal vulnerability in NKJPCorpusReader allows an attacker who can influence the fileids argument of its public read methods (header, raw, words, sents, tagged_words) to read files outside the corpus root. The reader builds the file path with no containment check and opens it with the builtin open(), so it bypasses NLTK's nltk.pathsec sandbox — including the strict ENFORCE = True mode that SECURITY.md recommends for web/multi-tenant deployments. header() returns the parsed content of the out-of-root file to the caller (arbitrary file read). Details SECURITY.md promises that file access is "validated against allowed NLTK data directories" and that with nltk.pathsec.ENFORCE = True "unauthorized file access … will raise PermissionError." That guarantee is enforced via FileSystemPathPointer.open() / CorpusReader.open(), which call nltk.pathsec.validate_path(...). NKJPCorpusReader never uses that protected path. In nltk/corpus/reader/nkjp.py: - add_root() builds the path by plain string concatenation with no normalization or containment check: def add_root(self, fileid): # lines 96-102 if self.root in fileid: return fileid # attacker-controlled value returned unchanged return self.root + fileid # plain concat, '..' not stripped - The header view appends a fixed basename and passes the string straight into the corpus view (which opens it with the builtin open()): class NKJPCorpus_Header_View(XMLCorpusView): # line 181 def init(self, filename, **kwargs): XMLCorpusView.init(self, filename + "header.xml", self.tagspec) # line 189 - The other modes reach the filesystem through XML_Tool, which uses a raw os.path.join (not the hardened FileSystemPathPointer.join()) and the builtin open(): class XML_Tool: # line 243 def init(self, root, filename): self.read_file = os.path.join(root, filename) # line 251 def build_preprocessed_file(self): fr = open(self.read_file) # line 256 — pathsec never consulted Because open() is the builtin (not PathPointer.o

Details

Source
GitHub Security Advisories (INTL · database · site)
Severity
high — CVSS 7.5
Published
2026-07-31
Last updated
2026-07-31
Exploitation
Not in CISA KEV at last sync

Original advisory: https://github.com/advisories/GHSA-6hm5-jgcp-p838

Referenced CVEs

CVECSIRTS overviewExternal
CVE-2026-12072coverage & exploitation statusNVD · CVE.org

More from GitHub Security Advisories