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

CVE-2026-81724

mediumCVSS 5.3covered by 2 sourcesfirst seen 2026-08-27
Summary nltk.featstruct.FeatStructReader (used by FeatStruct(str) and by FeatureGrammar.fromstring()) parses feature-structure strings such as [a=1] with a recursive-descent parser that has no nesting-depth limit. A small, trivially-crafted input (~700 bytes) with deeply nested brackets drives the parser past Python's recursion limit and raises an unhandled RecursionError instead of the library's normal, catchable ValueError/LogicalExpressionException. Any application that parses user-supplied feature-structure or feature-grammar text (e.g. NLP teaching tools, grammar "playgrounds", unification-grammar-based NLU pipelines) can be crashed by an unauthenticated input with no special privileges. This is a Denial of Service issue (CWE-674, Uncontrolled Recursion), not a memory-safety or code-execution issue. This appears to be the same bug class as two issues already fixed elsewhere in the codebase — nltk/jsontags.py (JSONTaggedDecoder.decode_obj, guarded by MAX_DECODE_DEPTH = 200) and nltk/sem/logic.py (LogicParser, guarded by MAX_PARSE_DEPTH = 200) — but nltk/featstruct.py does not have an equivalent guard. Details The recursive call chain (current develop branch, nltk/featstruct.py): 1. FeatStructReader.fromstring() (featstruct.py:2184) calls read_partial() → _read_partial() (featstruct.py:2250). 2. _read_partial() dispatches to _read_partial_featdict(), which calls _read_value() (featstruct.py:2436) for each feature's value. 3. _read_value() calls read_value() (featstruct.py:2442), which matches the value against VALUE_HANDLERS (featstruct.py:2478). 4. If the value itself starts with (a nested feature structure), the matched handler is read_fstruct_value ([featstruct.py:2479, defined at featstruct.py:2495): def read_fstruct_value(self, s, position, reentrances, match): return self.read_partial(s, position, reentrances) This calls read_partial() again, which re-enters _read_partial() — the same function from step 1. This closes a recursive cycle (_read_partia

⚡ Watch CVE-2026-81724

Get an email if CVE-2026-81724 is added to CISA KEV, gains public exploit code, or a new advisory cites it — max one per day, one-click unsubscribe.

Exploitation outlook

Advisory coverage (2)

External references

NVD record for CVE-2026-81724

CVE.org record

Embed the live status

CVE-2026-81724 live status badge — this badge updates automatically when the KEV or exploit status changes. How to embed it →

[![CVE-2026-81724 status](https://www.csirts.com/badge/CVE-2026-81724)](https://www.csirts.com/cve/CVE-2026-81724)