Skip to content

fix: protect URL downloads against SSRF with pinned DNS - #10125

Open
banned2054 wants to merge 2 commits into
AstrBotDevs:masterfrom
banned2054:fix/url-download-ssrf
Open

banned2054 wants to merge 2 commits into
AstrBotDevs:masterfrom
banned2054:fix/url-download-ssrf

Conversation

@banned2054

@banned2054 banned2054 commented Sep 18, 2026

Copy link
Copy Markdown

Fixes #10122

URL-based file and image downloads could reach private services through a direct URL, a DNS response, or a redirect. This change validates each destination before requesting it and pins the validated DNS results to the connection.

Modifications / 改动点

  • Protect download_file and download_image_by_url in the shared download layer: accept HTTP(S) URLs without embedded credentials and reject non-public IPv4/IPv6 destinations by default.

  • Use yarl hostname normalization, a resolver with no unchecked fallback, and explicit redirect validation. Apply the same policy to GET, POST, and TLS fallback requests.

  • Preserve access to explicitly configured self-hosted T2I endpoints. For Telegram voice/audio downloads, permit custom private file services while restricting the initial request and every redirect to the configured scheme, host, and port.

  • Document the proxy compatibility change in both English and Chinese configuration guides.

  • This is NOT a breaking change. / 这不是一个破坏性变更。

Compatibility: Protected downloads now connect directly with trust_env=False. They no longer use HTTP(S) environment proxies, because proxy-side DNS resolution would bypass the pinned destination. Deployments requiring a proxy need a directly reachable download URL or an appropriate application-level mirror. Existing callers downloading private URLs must explicitly opt into trusted private destinations.

Screenshots or Test Results / 运行截图或测试结果

Verification on Windows using the project virtual environment:

python -m pytest tests/unit/test_io_download_file.py tests/test_telegram_adapter.py -q -p no:cacheprovider
47 passed, 1 warning

ruff check .
All checks passed!

ruff format --check .
513 files already formatted

git diff --check
(no errors)

The warning is the existing audioop deprecation warning. Tests cover blocked IP/DNS destinations, IDNA normalization, redirect validation, trusted-origin restrictions, proxy settings, POST handling, TLS fallback behavior, and Telegram integration. A real aiohttp connector test uses a mocked hostname and a local server with a same-origin redirect, asserting one DNS lookup per validation step and no additional lookup when either connection is opened.

Checklist / 检查清单

  • New features have been discussed with the authors. Not applicable: this is a bug fix for [Bug] 通过URL发送文件功能缺少SSRF防护,存在内网探测风险 #10122.
  • Verification steps and test results are provided above.
  • Documentation impact reviewed: English and Chinese proxy notes updated; no WebUI navigation, structure, or label changes requiring screenshots or an entry mapping.
  • No new dependencies introduced.
  • No malicious code introduced.

Summary by Sourcery

Protect outbound media downloads against SSRF while preserving controlled access for trusted self-hosted services.

New Features:

  • Add SSRF-safe URL downloads with DNS validation, pinned connection addresses, redirect checks, and support for GET, POST, and TLS fallback requests.
  • Allow explicitly configured self-hosted T2I endpoints and custom Telegram file services to access private origins under origin restrictions.

Bug Fixes:

  • Prevent file and image downloads from reaching private or otherwise unsafe destinations through direct URLs, DNS responses, or redirects.
  • Ensure locally materialized images are used instead of private file-service URLs when converting or rendering media.

Enhancements:

  • Prefer local media paths across image conversion and Satori rendering, while preserving configured file-service URLs for distribution.
  • Disable environment HTTP(S) proxy use for protected downloads and document the resulting deployment requirements.

Documentation:

  • Document the proxy compatibility implications of SSRF-protected downloads in English and Chinese configuration guides.

Tests:

  • Add coverage for blocked private addresses and DNS results, IDNA normalization, origin and redirect restrictions, proxy behavior, POST requests, TLS fallback, pinned DNS connections, Telegram integrations, and self-hosted T2I rendering.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!

Sourcery assessment

Needs a human reviewer. This changes the outbound-request trust boundary for all protected downloads: a validation or redirect/DNS-pinning mistake could let attacker-controlled URLs reach private services and feed their responses into the application. Reverting would stop future requests but would not undo any internal data already fetched or processed.


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

@silvaling

Copy link
Copy Markdown

🔴 [blocking] 自建私网 T2I 端点在 return_url 路径下会被新策略拦掉

本 PR 为私网自建渲染端点留的 allow_private_network 豁免,只覆盖了 return_url=False 分支;本体默认走的 return_url=True 路径没有被覆盖。

链路(master 行号)

  1. pipeline/result_decorate/stage.py:382render_t2i(..., return_url=True):400 变成 Image.fromURL(url)
  2. utils/t2i/network_strategy.py:189f"{endpoint}/{id}",endpoint 即 t2i_endpoint,可为私网
  3. 发送侧取本地文件:QQ aiocqhttp_message_event.py:38-40convert_to_base64();Telegram tg_event.py:312、WebChat message_parts_helper.py:418、Lark/Slack/企微 走 convert_to_file_path()
  4. 两条都落到 utils/media_utils.py:486download_file(...),此处 allow_private_network 默认 False
  5. 本 PR 的豁免加在 network_strategy.py:193-203,即另一条分支

影响t2i_endpoint 指向私网自建的部署,渲染成功但图片随后被拦、发不出图;官方端点与公网端点不受影响。t2i_use_file_service=True 也无法规避(message/components.py:575 同样要下载)。

备注:静态链路追踪,未实机复现。


🤖 本评论由 AI 生成,结论已基于仓库代码核实;如有出入,以维护者判断为准。

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.

[Bug] 通过URL发送文件功能缺少SSRF防护,存在内网探测风险

2 participants