fix(security): add URL safety check to image_ref fetch in openai image_gen (SSRF) - #56035
fix(security): add URL safety check to image_ref fetch in openai image_gen (SSRF)#56035AlexFucuson9 wants to merge 1 commit into
Conversation
…e_gen The _load_image_bytes() function fetches arbitrary URLs passed via the `ref` parameter (from model tool calls) without any URL safety validation. A model-supplied URL pointing to cloud metadata endpoints (e.g. http://169.254.169.254/...) or internal network addresses allows server-side request forgery (SSRF) through the gateway. Add is_safe_url() check from tools.url_safety before fetching, matching the pattern already used in vision_tools.py, web_tools.py, skills_hub.py, and platform adapters (Slack, Mattermost). Ref: NousResearch#54553 (previous SSRF fix attempt, not merged)
Duplicate of #54553 — that earlier open PR adds the identical |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for addressing the unguarded OpenAI image-reference fetch; current main still has the direct requests.get(ref, timeout=60) path at plugins/image_gen/openai/__init__.py:134-140.
Problems
- The new initial
is_safe_url(ref)check does not cover redirects.requests.get()follows redirects by default, so a public URL can redirect to a metadata/private address.tools/vision_tools.py:405-417documents this exact bypass and re-validates every redirect target. - The PR changes no tests.
tests/plugins/image_gen/test_openai_provider.py:127-186currently covers local-file and data-URI loading only, not URL or redirect SSRF behavior.
Suggested changes
- Validate every redirect hop (or use a redirect-safe downloader) rather than only the initial URL.
- Add mocked direct-unsafe-URL and public-to-private-redirect regression tests.
Automated hermes-sweeper review.
| if lower.startswith(("http://", "https://")): | ||
| from tools.url_safety import is_safe_url | ||
|
|
||
| if not is_safe_url(ref): |
There was a problem hiding this comment.
requests.get() follows redirects by default, so this only validates the first hop. A public URL can still redirect to a metadata/private address; validate every redirect target before issuing its request, as tools/vision_tools.py:405-417 does.
## Summary - Harden `_load_image_bytes` so redirect hops are re-checked with `is_safe_url` (`allow_redirects=False`). - Close the gap where a pre-check alone still followed a malicious `Location` into metadata/private hosts. - Add focused regression tests. ## Salvage / credit Incomplete prior fixes NousResearch#54553 / NousResearch#56035 (pre-check without redirect hop validation).
Problem (P1 Security — SSRF)
The
_load_image_bytes()function inplugins/image_gen/openai/__init__.pyfetches arbitrary URLs passed via therefparameter from model tool calls without any URL safety validation:A model-supplied URL can point to:
http://169.254.169.254/latest/meta-data/...) — leaks AWS/GCP/Azure credentialshttp://10.0.0.1:8080/admin) — scans/exfiltrates internal serviceshttp://127.0.0.1:6379/) — accesses Redis, databases, etc.This is a server-side request forgery (SSRF) vulnerability through the gateway process.
Fix
Add
is_safe_url()check fromtools.url_safetybefore fetching, matching the pattern already used in:tools/vision_tools.py:212— image URL validationtools/web_tools.py:100— web search URL validationtools/skills_hub.py:40— skill URL validationplugins/platforms/slack/adapter.py:1646— Slack attachment validationplugins/platforms/mattermost/adapter.py:500— Mattermost attachment validationScope
Only the openai image_gen plugin fetches user-supplied URLs via
ref. Other image_gen plugins (krea, xai, openrouter) only call their respective API endpoints with server-controlled URLs — no SSRF risk.Testing
python3 -m py_compile plugins/image_gen/openai/__init__.py— OKis_safe_urlfunction blocks private IPs (10.x, 172.16-31.x, 192.168.x), link-local (169.254.x), localhost, and metadata endpointsRef: #54553 (previous SSRF fix attempt, not merged)