fix(entity): defuse entity-candidate ReDoS on long ASCII runs (#2063) - #2065
Closed
mvalentsev wants to merge 1 commit into
Closed
fix(entity): defuse entity-candidate ReDoS on long ASCII runs (#2063)#2065mvalentsev wants to merge 1 commit into
mvalentsev wants to merge 1 commit into
Conversation
…ace#2063) The English entity-candidate pattern in i18n/en.json backtracks catastrophically on a long unbroken run of printable ASCII (base64, minified JS, hashes, data URIs), pinning `mempalace mine` on a single ~5000-char window for hours. Collapse such runs to a space before single-word candidate matching, in both consumers that apply the pattern (palace._candidate_entity_words and entity_detector.extract_candidates). Scoped to ASCII ([!-~]) so non-ASCII scripts stay untouched — a CJK paragraph is one unbroken run with no ASCII whitespace, and zh-CN/zh-TW have no multi-word fallback, so a blanket collapse would erase their detection. Threshold 24 sits above the 20-char cap of the simple-name pattern, so no real name is dropped. Fixes MemPalace#2063. Co-authored-by: Ryan Wei <9876551+RyanWei@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mvalentsev
marked this pull request as ready for review
July 23, 2026 08:31
3 tasks
1 task
igorls
added a commit
that referenced
this pull request
Aug 2, 2026
fix(entity): defuse entity-candidate ReDoS on long ASCII runs (#2065)
jjcav84
pushed a commit
to jjcav84/mempalace
that referenced
this pull request
Aug 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2063.
What does this PR do?
mempalace minecan pin a CPU core for hours (39h reported) on a single entity-extraction window. The English entity-candidate pattern ini18n/en.json([A-Z][a-z]+(?:[A-Z][a-z]+|[A-Z]{2,})+|[A-Z][a-z]{1,19}) backtracks catastrophically on a long unbroken run of printable ASCII — base64, minified JS, hashes, data URIs — which turn up routinely in transcripts and code files. Ondevelop,"Aa" + "B"*36already takes ~3s insidefindall, and a real ~5000-char base64 window never returns. The pattern is compiled and run in two places —palace._candidate_entity_words(the traceback in the issue) andentity_detector.extract_candidates— and both hang.Possessive quantifiers would fix the regex directly, but they're 3.11+ and the project supports 3.9 (pattern compilation is wrapped in
try/except re.error: continue, so a 3.11-only construct would silently disable English extraction on older Pythons). Instead this collapses long unbroken ASCII runs to a space before single-word candidate matching, in both places. Such a run is never a name, so real entity output is unchanged.The collapse is restricted to ASCII (
[!-~]) on purpose: base64/hashes are always ASCII, so it still catches every reported case, but it leaves CJK, Cyrillic, Devanagari and accented-Latin text alone. A blanket\Sversion would have wiped out Chinese detection — Chinese has no ASCII whitespace, so a whole paragraph is one unbroken run, and zh-CN/zh-TW have no multi-word fallback. The threshold (24) sits just above the 20-char cap of the simple-name pattern ([A-Z][a-z]{1,19}), so no ordinary name is affected. Onlyen.json's candidate pattern has the ambiguous nested-repetition shape, so other locales can't regress either.How to test
Before this PR the following never returns; after, it's instant:
New tests cover the collapse and its 23/24 boundary, that non-ASCII runs are never collapsed, that a Chinese paragraph still yields entities (zh regression guard), a hypothesis property that no input can leave a collapsible run, and a subprocess/timeout test that runs the real payload through both consumers so a regression fails fast instead of hanging (there's no
pytest-timeouthere).Checklist
python -m pytest tests/ -v)ruff check .)Based on @RyanWei's proposed fix in #2063, extended to both call sites, scoped to ASCII so CJK detection keeps working, with the threshold lowered to 24.