Skip to content

fix(utils.url): require boundary char in withBase prefix match (#564)#576

Open
SAY-5 wants to merge 1 commit into
unjs:mainfrom
SAY-5:say5-fix-withbase-ssrf-boundary
Open

fix(utils.url): require boundary char in withBase prefix match (#564)#576
SAY-5 wants to merge 1 commit into
unjs:mainfrom
SAY-5:say5-fix-withbase-ssrf-boundary

Conversation

@SAY-5
Copy link
Copy Markdown

@SAY-5 SAY-5 commented May 12, 2026

Fixes #564.

withBase(input, base) previously returned input unchanged whenever input.startsWith(base) was true. An attacker-controlled input like http://api.internal.attacker.com/steal satisfies startsWith("http://api.internal") and bypasses the base-URL enforcement, reaching an arbitrary host (CWE-918 SSRF / authority-override).

This change requires the character after the base to be a URL boundary (/, ?, #) or end-of-string before short-circuiting. Otherwise the input is joined with the base as a path segment, matching what callers using baseURL expect.

Adds test/utils.url.test.ts with 8 unit tests covering existing behaviour (/, ?, #, exact match, no-base, base-less input) and the new boundary guard. The regression test fails on the pre-fix code and passes after.

Full suite: pnpm vitest run -> 36/36 passing.

Summary by CodeRabbit

  • Bug Fixes

    • Fixed URL base-joining logic to correctly validate boundary characters when determining if input already includes the base path.
  • Tests

    • Added comprehensive test coverage for URL base handling, including boundary edge cases.

Review Change Stack

)

withBase previously short-circuited and returned the input unchanged
whenever the input merely had the base string as a prefix. An attacker
controlling the input could craft a URL like
http://api.internal.attacker.com/steal that satisfies startsWith for the
base http://api.internal, bypassing the join and reaching an arbitrary
host (CWE-918 SSRF / authority-override).

The prefix match now requires the next character after the base to be a
URL boundary (/, ?, #) or end-of-string. Adds 8 unit tests covering the
existing behaviour and the new boundary guard.

Signed-off-by: SAY-5 <say.apm35@gmail.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 12, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a7ddd53a-a4a1-4222-b1f8-92d833f5710a

📥 Commits

Reviewing files that changed from the base of the PR and between dfbe3ca and d27664d.

📒 Files selected for processing (2)
  • src/utils.url.ts
  • test/utils.url.test.ts

📝 Walkthrough

Walkthrough

The PR fixes a Server-Side Request Forgery (SSRF) vulnerability in withBase by requiring a valid URL boundary character (/, ?, #, or end-of-string) immediately after the base URL when determining if an input already includes the base. Previously, a simple .startsWith() check allowed attacker-controlled inputs like http://api.internal.attacker.com to bypass a http://api.internal base URL enforcement.

Changes

SSRF Boundary Validation

Layer / File(s) Summary
Boundary check documentation and implementation
src/utils.url.ts
Documentation clarifies the new URL boundary requirement for the short-circuit condition, and the withBase function now validates that the character immediately following _base is a valid boundary (/, ?, #, or undefined) before returning the input unchanged.
SSRF boundary validation tests
test/utils.url.test.ts
New test suite covers empty base, root base, path joining, exact-match and boundary cases for ? and #, and a regression test that validates boundary-less prefix matches are properly joined instead of short-circuited.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

A rabbit hops through URLs with care,
Checking boundaries here and there,
No sneaky prefixes slip on by,
When / marks the honest divide,
SSRF attacks must now surrender their might! 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main fix: adding a boundary character requirement to the withBase prefix match to address the SSRF vulnerability.
Linked Issues check ✅ Passed The code changes implement the exact fix specified in issue #564: boundary validation for URL separators (/, ?, #, or end-of-string) before short-circuiting in withBase, with comprehensive test coverage for the SSRF scenario.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the SSRF vulnerability: boundary check logic in withBase and corresponding unit tests validating the fix and regression prevention.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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.

SSRF via Unconstrained baseURL + Open Redirect

1 participant