fix(security): block SSRF in fetch_image_url via scheme allowlist and private IP rejection#2134
Open
5F0jd2vLq54RerYW wants to merge 2 commits into
Open
fix(security): block SSRF in fetch_image_url via scheme allowlist and private IP rejection#21345F0jd2vLq54RerYW wants to merge 2 commits into
5F0jd2vLq54RerYW wants to merge 2 commits into
Conversation
… private IP rejection Adds URL validation to fetch_image_url() before issuing any HTTP request: - Scheme allowlist: only http/https permitted; file://, ftp://, etc. raise ValueError - Metadata host blocklist: rejects 169.254.169.254 (AWS IMDSv1), metadata.google.internal (GCP), 169.254.170.2 (Azure IMDS) - Literal IP rejection: ipaddress.ip_address() detects private, loopback, and link-local literal IPs; raises ValueError before session.get() is called. Hostnames (non-literal IPs) are not blocked — DNS rebinding protection is deferred to a future change. Tests (12 cases) verify that session.get() is never called for rejected URLs by mocking create_http_session and asserting zero .get() calls. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Author
|
Note: nix is not available in this dev environment, so I ran |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
fetch_image_url()inchat_completions.pyfetches arbitrary URLs provided by API clients with no validation. This allows SSRF attacks:http://169.254.169.254/latest/meta-data/iam/security-credentials/leaks AWS IAM credentialshttp://192.168.1.1/adminscans the internal networkfile:///etc/passwdreads local files (if aiohttp supports the scheme)Fix
Adds three validation checks before
session.get()is ever called:http/httpspermittedipaddress.ip_address(hostname)detects private, loopback, and link-local IPs; DNS hostnames are not blocked (DNS rebinding protection is deferred)No new package dependencies — uses only stdlib
ipaddressandurllib.parse.Tests
12 test cases in
src/exo/api/adapters/tests/test_fetch_image_url.py:session.get()is never called (mock +assert_not_called())Scope
In scope: Literal IP validation at parse time.
Out of scope: DNS rebinding (hostname → private IP after resolution). That requires resolving hostnames before connecting, which is a larger change best handled separately.
🤖 Generated with Claude Code