{"id":"CVE-2026-81725","aliases":["GHSA-8mpw-7fpc-4gqj","PYSEC-2026-3752"],"url":"https://o3.security/vulnerability/CVE-2026-81725","summary":"NLTK before 3.10.3 Regular Expression Denial of Service via Pl196xCorpusReader","details":"### Summary\n\n`Pl196xCorpusReader` still parses whole TEI blocks with multiple lazy regexes over attacker-controlled text. A malformed file with many opening tags and no matching closing tags forces repeated rescans and produces quadratic CPU growth in public reader APIs.\n\n### Details\n\n- **Vulnerability type:** Regular-expression denial of service\n- **Affected component:** `nltk.corpus.reader.pl196x.TEICorpusView.read_block` and `Pl196xCorpusReader` public methods\n- **Affected versions:** Published `3.9.4` and current source `v3.10.0-rc2` both reproduced.\n- **Patched versions:** Not yet patched\n- **Root cause:** Lazy `.*?` whole-block regexes rescan untrusted XML-like blocks from each opening-tag position.\n\nThe parser uses regexes for paragraphs, sentences, and word tags across the whole `<text>` block. When the attacker supplies many unmatched opening tags, each attempt scans toward the end of the block and fails, then restarts from the next opening tag. There is near four-times runtime growth each time the number of malformed `<p>` tags doubled, through normal public calls such as `words()` and `tagged_words()`.\n\n### PoC\n\n**Preconditions**\n- The application parses attacker-influenced PL196X or TEI-like corpus files through public reader APIs.\n\n**Steps**\n1. Create a corpus file with a valid header followed by a `<text>` block that contains many opening tags and no matching closing tags.\n2. Instantiate `Pl196xCorpusReader` on that corpus.\n3. Call `words()` or `tagged_words()` and measure elapsed time as the malformed tag count doubles.\n4. Observe near quadratic growth instead of near-linear behavior.\n\n**Minimal reproducible excerpt**\n\n```text\nsize=1000 0.014s\nsize=2000 0.057s\nsize=4000 0.231s\nsize=8000 0.927s\n```\n\n### Impact\n\nA consumer that accepts attacker-influenced corpus files can be forced into heavy CPU use and parser-thread stalling before the application concludes the input contains no valid content.\n\n### Remediation\n\nReplace the whole-block lazy-regex parser with a linear parser or bounded tokenizer, and add regression tests that assert near-linear behavior on malformed inputs with many unmatched tags.","published":"2026-08-27T14:51:18.082Z","modified":"2026-10-21T03:00:00.634819081Z","cvss":null,"epss":{"score":0.00229,"percentile":0.13876,"asOf":"2026-09-17"},"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"PyPI","name":"nltk","fixedVersion":"3.10.3"}],"fix":{"url":"https://github.com/nltk/nltk/commit/7808692d451b962711005d954859bb83aabcf8fa","label":"nltk/nltk@7808692"},"references":[{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/81xxx/CVE-2026-81725.json"},{"type":"ADVISORY","url":"https://github.com/nltk/nltk/security/advisories/GHSA-8mpw-7fpc-4gqj"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-81725"},{"type":"ADVISORY","url":"https://www.vulncheck.com/advisories/nltk-before-3.10.3-regular-expression-denial-of-service-via-pl196xcorpusreader"},{"type":"WEB","url":"https://github.com/nltk/nltk/commit/7808692d451b962711005d954859bb83aabcf8fa"},{"type":"PACKAGE","url":"https://github.com/nltk/nltk"},{"type":"WEB","url":"https://github.com/nltk/nltk/releases/tag/v3.10.3"},{"type":"WEB","url":"https://github.com/pypa/advisory-database/tree/main/vulns/nltk/PYSEC-2026-3752.yaml"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-10-21T03:00:00.634819081Z"}}