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)

Đang mở
#2,432 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
Python
Star
15.9k
Fork
1.4k
Merge trung bình
1 ngày 17 giờ
Pull request đã merge (30 ngày)
163

Mô tả

# 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.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.