Skip to content

fix(vl): re-validate every redirect hop when fetching image_url (SSRF #4761)#4762

Closed
Anai-Guo wants to merge 2 commits into
InternLM:mainfrom
Anai-Guo:fix/ssrf-redirect-revalidate
Closed

fix(vl): re-validate every redirect hop when fetching image_url (SSRF #4761)#4762
Anai-Guo wants to merge 2 commits into
InternLM:mainfrom
Anai-Guo:fix/ssrf-redirect-revalidate

Conversation

@Anai-Guo

Copy link
Copy Markdown

Summary

Fixes #4761 — an unauthenticated SSRF in the multimodal image_url fetch path. The private-IP guard _is_safe_url was applied only to the original URL, after which the response was fetched with allow_redirects=True. requests follows a 302 Location without re-running the guard, so an attacker-controlled public host (which passes the guard) can redirect to http://127.0.0.1:.../ or http://169.254.169.254/... and have the internal/metadata bytes returned through the image pipeline. On the default 0.0.0.0 + no-auth server, any client of a vision deployment can reach this.

Fix

_load_http_url now follows redirects manually with allow_redirects=False, and re-runs _is_safe_url on each resolved Location before following it. The redirect budget (max_redirects = 3) is preserved. Non-http(s) schemes are already rejected by _is_safe_url, so a redirect can no longer switch to a disallowed scheme either.

Verification

Local unit-level reproduction against the changed function (no GPU / model download):

  • Direct internal URL → blocked (unchanged).
  • Public host that 302-redirects to an internal target → now blocked at the redirect hop with URL is blocked for security reasons: ... (previously the internal bytes were returned).
  • Normal same-origin / public redirects still succeed within the 3-hop budget.

This keeps the change tight to the reported redirect-bypass. Connection-level IP pinning (DNS-rebinding hardening) and default-auth are separate concerns noted in the issue and are intentionally left out of scope here.

🤖 Generated with Claude Code

Anai-Guo added 2 commits July 18, 2026 09:11
_load_http_url ran the private-IP guard (_is_safe_url) only on the
original URL, then fetched with allow_redirects=True. requests follows
a 302 without re-checking, so a public host that passes the guard could
redirect to an internal or cloud-metadata address and have its bytes
returned through the image pipeline. Follow redirects manually and run
_is_safe_url on each Location before following it.

Fixes InternLM#4761
@Anai-Guo

Copy link
Copy Markdown
Author

Pushed a follow-up to fix the failing unit test: the existing test_load_http_url_logic asserted the old allow_redirects=True behaviour and its mock response had a truthy is_redirect, which now exercises the manual redirect path. Updated it to the non-redirect success case (allow_redirects=False) and added test_load_http_url_revalidates_redirect_target to cover the SSRF fix itself (a 302 to 169.254.169.254 is now rejected).

@lvhan028

Copy link
Copy Markdown
Collaborator

Hi, thanks for the PR. Since #4734 already addresses this issue and has broader test coverage for redirect/allowlist edge cases, I am going to close this one in favor of that.

@lvhan028 lvhan028 closed this Jul 20, 2026
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.

Unauthenticated SSRF via image_url in the OpenAI-compatible chat endpoint (redirect bypass of the private-IP guard)

2 participants