fix(platforms): guard media redirects against SSRF - #55942
Conversation
Related to the SSRF-redirect-guard cluster: merged #54470 (yuanbao) and #7151 (Slack), and open #22340 / #43938 (yuanbao) and #24831 (Mattermost). Same vulnerability class (initial |
|
looks mergeable Security evidence:
Review setup note: I reviewed a run-owned local merge/replay setup against current GitHub Signed: GPT-5.5-xhigh in Codex |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for covering the Feishu download path and for retaining a defensive final-URL check for injected WeCom clients.
Problems
- Blocking: The WeCom hook only applies to the fallback client at
plugins/platforms/wecom/adapter.py:1082-1086in PR6ba1accba85e. In normal operation,connect()creates and storesself._http_clientwithfollow_redirects=Truebut no hook atplugins/platforms/wecom/adapter.py:222-224;_download_remote_bytes()prefers that client. The new check at PR line 1098 runs only after httpx has followed the redirect and received the final response, so it cannot prevent the SSRF request itself.
Suggested changes
- Attach
_ssrf_redirect_guardto the persistent client created byconnect()and add a test for that construction path. Keep the final-URL check as defense for injected clients that do not carry the hook.
Automated hermes-sweeper review.
| client = self._http_client or httpx.AsyncClient( | ||
| timeout=30.0, | ||
| follow_redirects=True, | ||
| event_hooks={"response": [_ssrf_redirect_guard]}, |
There was a problem hiding this comment.
This hook only protects the fallback client. A connected adapter uses self._http_client, which connect() constructs with follow_redirects=True and no event hook (adapter.py:222-224 on current main). The final-URL check below happens after the redirected request, so please install this guard on that persistent client as well.
|
superseded Current Security evidence:
Not checked:
Signed: GPT-5.6-sol-xhigh in Codex |
Summary
This closes redirect-based SSRF gaps in Feishu and WeCom remote media/document downloads.
Why
Both paths validated the initial URL with
is_safe_url(), but then downloaded withfollow_redirects=True.That leaves a redirect gap: an attacker-controlled public URL can pass the initial safety check and then redirect to a private/internal address such as cloud metadata. The shared gateway redirect guard already exists for this exact class; these paths were not using it.
Affected paths:
plugins/platforms/feishu/adapter.py::_download_remote_documentplugins/platforms/wecom/adapter.py::_download_remote_bytesChanges
_ssrf_redirect_guardto Feishu remote document downloadhttpx.AsyncClient._ssrf_redirect_guardto owned WeCom download clients.response.urlsafety check in WeCom so injected/shared clients that do not carry the event hook still cannot return redirected internal content.Tests