Skip to content

fix(websearch): block non-public URLs in page fetching - #1020

Open
SiyuanChenToDo wants to merge 1 commit into
modelscope:mainfrom
SiyuanChenToDo:fix/block-non-public-fetch-urls
Open

SiyuanChenToDo wants to merge 1 commit into
modelscope:mainfrom
SiyuanChenToDo:fix/block-non-public-fetch-urls

Conversation

@SiyuanChenToDo

Copy link
Copy Markdown

Summary

WebSearchTool.fetch_page accepted arbitrary model-supplied URLs and passed
them to Jina Reader, the direct urllib fallback, and the Playwright fallback
without restricting the destination. This allowed SSRF against loopback,
RFC1918, link-local, multicast, and cloud-metadata addresses (for example
169.254.169.254 and 100.100.100.200), and redirects were followed without
re-validation.

This adds ms_agent/tools/url_safety.py:

  • accepts only http/https URLs with a hostname;
  • resolves the hostname and rejects the request if any resolved address is
    loopback, private, link-local, multicast, reserved, unspecified, or
    otherwise non-global;
  • unwraps IPv4-mapped IPv6 addresses and strips IPv6 zone IDs;
  • rejects known metadata hostnames and .localhost / .local / .internal
    suffixes;
  • re-validates every redirect target in the urllib opener.

The check runs before Jina Reader, before the direct HTTP fallback, and on
every document navigation in the Playwright fallback, so a public URL cannot
redirect into an internal one. ContentFetcher now documents that local
fetchers must enforce this.

Fixes #1018

Test

  • pytest tests/tools/test_url_safety.py tests/tools/test_server_tools_smoke.py -q — 41 passed, 3 skipped
  • flake8 / yapf 0.32 / py_compile on changed files — passed
  • Reverting the Jina validation makes the regression test fail
  • New tests cover private IPv4/IPv6 ranges, IPv4-mapped loopback, mixed
    public/private DNS answers, metadata addresses, redirects, and the
    Jina/Playwright entry points

AI assistance

Prepared with AI assistance (Claude Code); I reviewed the diff, ran the tests,
and can explain and defend the change.

fetch_page accepted arbitrary model-supplied URLs and passed them to Jina Reader, the direct urllib fallback, and the Playwright fallback without restricting the destination. Resolve hostnames and reject loopback, private, link-local, multicast, reserved, and cloud-metadata addresses; re-validate every HTTP redirect; and re-check document navigations in the Playwright fallback.

Fixes modelscope#1018

Co-Authored-By: Claude Code <noreply@anthropic.com>

This branch has not been deployed

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

Labels

None yet

1 participant