🔒 Fix polynomial ReDoS in validation regexes - #8
Merged
Conversation
- Replace the frontmatter key regex with an index split - Stop link and XML tag patterns from rescanning on each offset - Compare trailing whitespace with endsWith instead of a regex - Accept CRLF frontmatter, which the opening regex rejected before - Coerce non-string descriptions instead of throwing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.
Summary
Fixes four high-severity
js/polynomial-redoscode scanning alerts by removing the ambiguous repetitions that let a crafted skill description consume seconds of CPU per validation.Closes the alerts reported in 5, 6, 7, and 8. Alerts 1–4 are the same defects at the pre-restructure
scripts/paths, so these are pre-existing issues re-detected after #1, not regressions from that stack.Impact
SKILL.mdfrontmatter is untrusted input read from disk.validateMicroTemplatereportsdesc.toolongabove 1024 characters but does not stop, so an oversized description still reaches every pattern below it. Measured on a 40,000-character adversarial input:\[[^\]]+\]\([^\)]+\)<[a-zA-Z][^>]*>[ \t]+$Alert 5 is not reachable through the current call path, because
extractFrontmattersplits on\nbefore applying the regex, so the subject can never contain the newline the quadratic path requires. It is fixed as a latent hazard.Changes
src/core/frontmatter.js: parsekey: valuewithindexOf(':')and a linear/^\w+$/key check instead of/^(\w+):\s*(.*)$/src/validate/micro-templates.js: narrow[^\]]+to[^\][]+and[^\)]+to[^()]+so a scan starting at[stops at the next[src/validate/micro-templates.js: narrow[^>]*to[^<>]*; an XML tag cannot contain<, and<a<b>is still reported because the scan restarts at the inner<src/validate/micro-templates.js: replace/[ \t]+$/withendsWith(' ') || endsWith('\t'), which is exactly equivalent without themflag and runs in constant timesrc/validate/micro-templates.js: coerce non-string descriptions innormalizeTextand share arawvalue with the NBSP and trailing checks, so a non-string argument no longer throwssrc/core/frontmatter.jsandsrc/validate/index.js: accept\r?\nin the frontmatter delimiter, fixing CRLFSKILL.mdfiles whose keys were silently droppedsrc/validate/index.js: harden the two heading patterns with[ \t]+instead of\s+for consistency, though CodeQL did not flag themAffected area
Core helpers and validation rules.
Checklist
npm run formatpasses with no unstaged diffs.npm testpasses with no new errors.README.mdis updated when CLI options, validation rules, or package exports change. Not applicable; validation rules are unchanged.package.jsonexportsandfilesare updated when modules are added, moved, or removed. Not applicable; no module changes.Security checklist
npm audit --audit-level=highreports no new high or critical findings.Verification
nullbefore and now parsesnpm testpassesnpx prettier --config-precedence prefer-file --check .reports no driftAdditional context
The CRLF fix turned out to be required rather than incidental. The original blocker was the opening delimiter on line 6, not the key pattern on line 17, so the key-parsing change alone would not have fixed it.
Stack
Part of a stacked PR series fixing the polynomial ReDoS code scanning alerts (bottom to top):
stoe/fix-redos-patterns)stoe/add-redos-tests)