Description
Second ReDoS sweep. These were found while verifying #173 (the #168 follow-ups). All of them predate #173. The first item is reachable without authentication; fix it before 0.6.5.
Must fix (unauthenticated, CPU per request)
- Email check runs before the length cap.
packages/api/src/routes/password-reset.ts:123(unauthenticatedPOST /request) andpackages/api/src/routes/invites.ts:213runEMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/(invites.ts:85) before checkingemail.length > 254. The domain part is ambiguous on dots, so"a@" + ".".repeat(n) + "@"backtracks in O(n²).jsonBody(packages/api/src/tokens.ts:41) has no size cap, so one request with a 100k-character email costs seconds of CPU. That kills the Worker on its CPU limit, or stalls the event loop on Node/Docker.limitPubliclimits how often a client can call, not how much each call costs.- Fix: check the length first in both places (Studio's
roles.ts:341already does). MakeEMAILlinear: a single@, then an indexOf check for the dot. - Fix: add a body size cap to
jsonBody(for example 64 KiB; return 413 above it) for the public token routes. - Tests: a 100k adversarial input completes in well under 100 ms, and an oversized body gets 413.
- Fix: check the length first in both places (Studio's
Should fix (request path or agent input)
-
packages/core-ts/src/redirects.ts:20normalisePathruns/\/+$/on every site request (astro-rendererrouting.ts:167,taxonomy.ts:1327redirectFor). Astro collapses duplicate slashes first, which mitigates it, but the result also feedsancestorPaths, which is O(n²) in memory on runs of slashes. Use a linear trim. Do the same forjoinTarget(redirects.ts:36) andpackages/schedules/src/feed-check.ts:217urlPath. -
apps/docs/src/worker/paths.ts:42:isPagePath = !/\.[^/]*$/.test(pathname)runs on every docs Worker GET."/" + ".".repeat(n) + "/"is O(n²), about 150 ms at 16 KB. Use a lastIndexOf check. -
Lazy scans that rescan to the end when the closer is missing, all on agent, editor or upload input:
packages/core-ts/src/search-rows.ts:43(fenced code at publish time)packages/core-ts/src/media/svg.ts:144(/\/\*[\s\S]*?\*\//gon uploaded SVG CSS)packages/schedules/src/feed-check.ts:157and:202packages/core-ts/src/automations.ts:450
For each one, measure with an adversarial input. Rewrite the ones that are superlinear with indexOf-based scanners.
-
packages/agent-runtime/src/skills.ts:39/^\s+([^:]+):\s*(.*)$/:\s+overlaps[^:]+, so a line of only spaces is O(n²). Check whether skill markdown can come from callers. Fix it either way, it is cheap. -
packages/ui/src/blocks/editor/markdown-blocks.ts:69,76/\n*$/: client-side, but a body written by an agent can reach it. Use a linear trim.
Done when
- Every rewrite has an equivalence test against the old regex on normal inputs and a 100k-character adversarial case.
- A short CONTRIBUTING or AGENTS.md note: avoid unanchored or end-anchored quantified runs and lazy scans on external input, and prefer indexOf scanners.
- Patch changesets for the published packages touched.
Activity
fix(security): review round 2 for the ReDoS sweep (#174)
test: align ReDoS timing bounds; code-point cap in ancestorPaths (#174)
Merge pull request #175 from cloudhal-dev/claude/redos-174