Skip to content

fix(worker-bundler): eliminate polynomial ReDoS in import/export regexes#1718

Open
mattzcarey wants to merge 1 commit into
mainfrom
fix/1537-redos-import-regex
Open

fix(worker-bundler): eliminate polynomial ReDoS in import/export regexes#1718
mattzcarey wants to merge 1 commit into
mainfrom
fix/1537-redos-import-regex

Conversation

@mattzcarey

@mattzcarey mattzcarey commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Note

This is a Fable experiment (model-authored PR). Please close if it adds no value.

Fixes #1537

Problem

rewriteImports (packages/worker-bundler/src/transformer.ts) matched import/export clauses with:

(?:[\w*{}\s,]+\s+from\s+)?

[\w*{}\s,]+ includes \s, so it overlaps with the adjacent \s+ — on near-match input the engine backtracks through every split of the whitespace between the two quantifiers. The issue's PoC reproduces on main:

input old regex new regex
import + 1k spaces + X 180 ms 0.1 ms
import + 5k spaces + X 22.7 s 0.0 ms
import + 10k spaces + X 175.6 s 0.0 ms

The same shape exists in two more places the issue didn't mention: parseImportsRegex in resolver.ts (importRegex and exportFromRegex) — the fallback parser that runs whenever es-module-lexer throws (e.g. on JSX/TSX), so it's reachable with untrusted module source too. Fixed all three.

Fix

Match the clause as non-whitespace tokens separated by whitespace:

[\w*{},]+(?:\s+[\w*{},]+)*

No two adjacent quantifiers can consume the same characters, so matching is linear. I considered the bounded-quantifier mitigation ({1,200}) but rejected it: it caps rather than removes the overlap (still ~2.7s at n=5000) and silently stops matching legitimately long clauses (a 200+ char multi-line named-import list).

Verified equivalent on a 15-case corpus (default/named/namespace/side-effect/mixed/multi-line imports, export {…} from / export * from, near-miss non-imports, dynamic import) and stress-tested the new pattern against other adversarial shapes (repeated from tokens, stacked near-matches, token tails) — all sub-20ms.

Tests

packages/worker-bundler/src/tests/redos.test.ts (new):

  • transformAndResolve on a 50k-space whitespace-bomb module completes in ms (bounded at 5s; old code takes tens of minutes at this size, so the bound is generous but unambiguous)
  • parseImports regex fallback (forced via JSX) on the same bomb completes in ms
  • All 8 import/export statement forms still rewrite correctly through transformAndResolve
  • The regex fallback still extracts every specifier form (static, named, namespace, side-effect, mixed, export … from, dynamic)

Full package suite: 185 passed (6 files) via pnpm test. Typecheck/oxfmt/oxlint clean.

Notes for maintainers

  • Behavior is unchanged for valid code; the only observable difference is performance on pathological input.
  • The reporter filed this through HackerOne first (triaged informative), so discussing the fix publicly here is fine.
  • The third occurrence (dynamicImportRegex) has no overlapping quantifiers and is untouched.
  • Changeset included (@cloudflare/worker-bundler patch).

Open in Devin Review

The clause sub-pattern [\w*{}\s,]+ followed by \s+ let both quantifiers
consume the same whitespace, backtracking polynomially on near-match
inputs (import + 10k spaces took ~175s). Match clauses as non-whitespace
tokens separated by whitespace instead — linear and behaviorally
equivalent. Applies to rewriteImports (transformer.ts) and the
parseImports regex fallback (resolver.ts), which had the same shape.

Fixes #1537
@changeset-bot

changeset-bot Bot commented Jun 9, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 9acd75d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@cloudflare/worker-bundler Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Jun 9, 2026

Copy link
Copy Markdown

Open in StackBlitz

agents

npm i https://pkg.pr.new/agents@1718

@cloudflare/ai-chat

npm i https://pkg.pr.new/@cloudflare/ai-chat@1718

@cloudflare/codemode

npm i https://pkg.pr.new/@cloudflare/codemode@1718

create-think

npm i https://pkg.pr.new/create-think@1718

hono-agents

npm i https://pkg.pr.new/hono-agents@1718

@cloudflare/shell

npm i https://pkg.pr.new/@cloudflare/shell@1718

@cloudflare/think

npm i https://pkg.pr.new/@cloudflare/think@1718

@cloudflare/voice

npm i https://pkg.pr.new/@cloudflare/voice@1718

@cloudflare/worker-bundler

npm i https://pkg.pr.new/@cloudflare/worker-bundler@1718

commit: 9acd75d

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 3 additional findings.

Open in Devin Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Polynomial-time ReDoS in module transformation process of @cloudflare/worker-bundler

1 participant