Skip to content

fix(security): add SSRF protection to gateway media downloads - #3151

Closed
dieutx wants to merge 1 commit into
NousResearch:mainfrom
dieutx:fix/ssrf-gateway-media-download
Closed

fix(security): add SSRF protection to gateway media downloads#3151
dieutx wants to merge 1 commit into
NousResearch:mainfrom
dieutx:fix/ssrf-gateway-media-download

Conversation

@dieutx

@dieutx dieutx commented Mar 26, 2026

Copy link
Copy Markdown
Contributor

Summary

cache_image_from_url and cache_audio_from_url in gateway/platforms/base.py have no SSRF protection. An attacker can send a message with an attachment URL pointing at http://169.254.169.254/latest/meta-data/ and the gateway fetches it.

Root Cause

Both functions use httpx.AsyncClient(follow_redirects=True) to fetch user-controlled URLs from platform attachments (Telegram photos, Discord attachments, Slack files, etc.) with no address validation. The is_safe_url check from tools/url_safety is already used in browser_tool.py, web_tools.py, and vision_tools.py — these two were missed.

Fix

Added is_safe_url pre-flight check to both download functions with a fail-closed import guard (lambda url: False if the module is unavailable). Raises ValueError on private/internal addresses before any HTTP request.

Tests

8 new tests: cloud metadata, localhost, private network, link-local (all blocked) + public URLs with mocked HTTP client (allowed).

8 passed

cache_image_from_url and cache_audio_from_url fetch user-controlled URLs
from platform message attachments (Telegram, Discord, Slack, etc.) with
httpx follow_redirects=True and no address validation.

An attacker sending a message with an attachment URL pointing to
http://169.254.169.254/latest/meta-data/ or any internal service could
use the gateway as an SSRF proxy.

Add is_safe_url pre-flight check (from tools/url_safety) with
fail-closed import guard, matching the pattern from browser_navigate.
@dieutx

dieutx commented Mar 26, 2026

Copy link
Copy Markdown
Contributor Author

Closing — the SSRF check on cache_image_from_url is already covered by #2690 which adds the same is_safe_url guard along with broader image format validation (magic bytes, SVG blocking, size limits). The cache_audio_from_url SSRF check here is unique but small enough to fold into #2690 if needed.

@dieutx dieutx closed this Mar 26, 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.

1 participant