fix(signals): linear-time manifest glob matcher (ReDoS) + **/ matches root + length cap#1366
Merged
Conversation
… root + glob length cap The manifest path matcher compiled `*` globs to a `.*`-per-star regex (`^.*a.*a...$`), which backtracks CATASTROPHICALLY on a near-miss path. A `.gittensory.yml` glob with many non-adjacent `*` (review.exclude_paths / when_paths / path_instructions[].path, or wantedPaths/blockedPaths) could hang the gate for an entire repo on Cloudflare's hard CPU limit — and the parsed manifest is cached, so every subsequent PR in that repo re-hits the hang. - Replace the regex with a LINEAR prefix + suffix + ordered-substring (indexOf) matcher — O(path × parts), no backtracking. `*`/`**` still match any run of chars across `/` (unchanged semantics). - A `**`-then-separator run now absorbs the mandatory slash, so a leading `**` glob also matches a ROOT-level file (e.g. exclude `**/*.test.ts` now excludes a root `app.test.ts`, not only nested). - Cap each glob / path_instructions path at MAX_ITEM_LENGTH (300) at parse time (defense-in-depth). Verified: a 20-star hostile glob against a 300-char near-miss returns in <100ms (previously >30s).
Contributor
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1366 +/- ##
=======================================
Coverage 95.35% 95.36%
=======================================
Files 191 191
Lines 20679 20696 +17
Branches 7475 7479 +4
=======================================
+ Hits 19719 19736 +17
Misses 378 378
Partials 582 582
🚀 New features to boost your workflow:
|
Closed
12 tasks
This was referenced Jul 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.
Summary
Adversarial-audit finding (high, 3/3 verifiers).
compileManifestPathMatchercompiled a*-glob to a.*-per-star regex (^.*a.*a…$) that backtracks catastrophically on a near-miss path. A.gittensory.ymlglob with many non-adjacent*(inreview.exclude_paths/when_paths/path_instructions[].path, orwantedPaths/blockedPaths) could hang the gate for an entire repo on Cloudflare's hard CPU limit — and the parsed manifest is cached, so every subsequent PR in that repo re-hits the hang.Changes
indexOf) scan: O(path × parts), no backtracking.*/**still match any run of chars across/(semantics unchanged for every existing case).**/matches root — a**-then-separator run absorbs the mandatory slash, so a leading**glob also matches a zero-depth/root file (e.g.**/*.test.tsnow excludes a rootapp.test.ts).path_instructions[].pathcapped atMAX_ITEM_LENGTH(300) at parse (defense-in-depth).From the 2026-06-25 multi-agent review-subsystem audit.
Validation
npm run test:ciexit 0 (4407 tests);npm auditclean; all changed lines+branches covered**/root, multi-wildcard correctness, a ReDoS regression (20-star glob vs 300-char near-miss <100ms, was >30s), length cap; all priormatchesManifestPathassertions still pass