Skip to content

fix: fail closed on non-HTTP(S) and link-local CCIP Read URLs - #5024

Open
SashaMIT wants to merge 2 commits into
wevm:mainfrom
SashaMIT:fix/ccip-request-url-fail-closed
Open

fix: fail closed on non-HTTP(S) and link-local CCIP Read URLs#5024
SashaMIT wants to merge 2 commits into
wevm:mainfrom
SashaMIT:fix/ccip-request-url-fail-closed

Conversation

@SashaMIT

Copy link
Copy Markdown
Contributor

ccipRequest fetched resolver-supplied gateway URLs with no scheme or host check, and fetch followed redirects.

A contract OffchainLookup can return file:///... or http://169.254.169.254/.... On Node that becomes a client-side request to a local file or link-local metadata address. A public URL that 302s to the same place had the same effect.

This is the URL-validation class web3.py already applies in validate_ccip_url_scheme / validate_ccip_url_host. Loopback HTTP stays allowed so local gateways and the existing test servers keep working. Callers who want a stricter allowlist can still wrap ccipRead.request.

Change

  • Reject non-http(s) schemes before fetch.
  • Reject IPv4 0.0.0.0/8 and 169.254.0.0/16, plus IPv6 unspecified and fe80: link-local literals.
  • Set redirect: 'manual' so a public gateway cannot bounce the client onto a blocked host.
  • If one URL in the list is blocked, try the next.

Test

SKIP_GLOBAL_SETUP=true pnpm exec vitest run -c ./test/vitest.config.ts --project core src/utils/ccipRequest.url.test.ts (4/4). Revert-tested: the three reject assertions fail when the pre-fetch guards are removed.

A resolver-supplied gateway URL could use file: or a link-local metadata address, and fetch followed redirects. Reject those hosts and schemes before the request, and do not follow redirects.
@vercel

vercel Bot commented Aug 18, 2026

Copy link
Copy Markdown

@SashaMIT is attempting to deploy a commit to the Wevm Team on Vercel.

A member of the Team first needs to authorize it.

@changeset-bot

changeset-bot Bot commented Aug 18, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 95e5b76

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

This PR includes changesets to release 1 package
Name Type
viem 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 Aug 18, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/viem@5024

commit: 95e5b76

@official-burak official-burak left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

IPv6 literals never hit the new block list. Node keeps brackets on URL.hostname, and v4-mapped link-local addresses are a second miss.

Comment thread src/utils/ccip.ts
}
}

function isBlockedCcipHostname(hostname: string) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Node's URL.hostname keeps brackets on IPv6 literals:

  • new URL('http://[::]/').hostname is '[::]'
  • new URL('http://[fe80::1]/').hostname is '[fe80::1]'
  • new URL('http://[::ffff:169.254.169.254]/').hostname is '[::ffff:a9fe:a9fe]'

None of those equal '::', start with 'fe80:', or match the dotted-quad regex, so the v6 and IPv4-mapped link-local cases this PR is meant to reject still go through to fetch.

Strip brackets before the checks. Run :ffff: mapped addresses through the same 169.254 / 0.0.0.0/8 rules.

Node keeps brackets on URL.hostname and rewrites ::ffff:a.b.c.d to hex, so the first pass missed those literals.
@SashaMIT

Copy link
Copy Markdown
Contributor Author

Good catch. Node keeps the brackets and rewrites the mapped form to hex, so those never hit the first checks.

The guard now strips brackets and runs v4-mapped addresses through the same 169.254 / 0.0.0.0/8 rules. Added tests for [::], [fe80::1], and [::ffff:169.254.169.254].

@official-burak

Copy link
Copy Markdown

Looks right. Stripping brackets and running v4-mapped addresses through the same 169.254 / 0.0.0.0/8 checks covers the two misses.

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.

2 participants