ag-ui-protocol / ag-ui-protocol/ag-ui

[BUG]: Agent-input URL sources fetched server-side without scheme or network-range validation (`file://` read, SSRF)

オープン
#2,432 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る
主要言語
Python
スター
15.9k
フォーク
1.4k
平均マージ
1日 17時間
マージ済み PR(30日)
163

説明

# Agent-input URL sources fetched server-side without scheme or network-range validation (`file://` read, SSRF)

Repository: https://github.com/ag-ui-protocol/ag-ui
Affected: `ag-ui-protocol` Python core (`InputContentUrlSource`), `ag_ui_strands` 0.3.0 (AWS Strands integration; `create_strands_app` is the documented production path incl. Bedrock AgentCore)
CWE: CWE-918 (Server-Side Request Forgery)

## Summary

`RunAgentInput` multimodal content permits `source: {type: "url", value: }`. The value is a bare string in the protocol model with no scheme or host validation. The aws-strands integration fetches it with `urllib.request.urlopen()` while building the model input history; urllib supports `file://`/`ftp://` and follows redirects.

## Affected code

- `sdks/python/ag_ui/core/types.py:91-96` — `InputContentUrlSource.value: str` (no constraints)
- `integrations/aws-strands/python/src/ag_ui_strands/utils.py:67-98` — fetch via `urllib.request.urlopen`, unbounded `resp.read()`
- Call path: `agent.py:604-615` (`convert_agui_content_to_strands`) → `_build_strands_history` (`agent.py:566`), invoked from `run()` at `agent.py:1886` — before any model call, with `replay_history_into_strands=True` by default
- TypeScript mirror: `integrations/aws-strands/typescript/src/utils.ts:78`

## Observed behavior (measured, against the real endpoint and conversion functions)

- `file:///` image source: the local file's full contents were read during input construction and embedded as a content block (verified end-to-end with a temporary file containing a credential-like string).
- `http://127.0.0.1:` source: a request was sent to the local port (internal reachability probing).
- The default `create_strands_app()` endpoint accepted the request (HTTP 200, SSE stream started); see the separate CORS report.

## Impact

A client can make the server read local files (`file:///etc/passwd`, credential files) or reach loopback/private/link-local endpoints (`http://169.254.169.254/...`). Fetched bytes become model input, so their content can be echoed back through the SSE response. The fetch occurs in mechanical preprocessing before any model or tool decision, so tool-authorization layers do not apply. `file://` has no legitimate purpose for the documented "fetch user-supplied image" function.

## Suggested remediation

- Enforce `https://` (optionally `http://`) at the protocol layer or integration boundary.
- Reject loopback/private/link-local ranges at connection time (pin the resolved IP; account for DNS rebinding).
- Cap response size and disable redirects.

コントリビューションガイド

コントリビューションガイドを開く

評価

この issue はまだ評価されていません。

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。