Repository navigation
fix(security): resolve profile update SSRF bypass and harden avatar fetch (#506) - #610
Open
rohanbuilds-ai wants to merge 3 commits into
Open
rohanbuilds-ai wants to merge 3 commits into
rohanbuilds-ai wants to merge 3 commits into
Conversation
…etch (GenAI-Security-Project#506) - Validate avatar_url against blocked IPv4, IPv6, loopback, and metadata ranges - Prevent validation bypass when updating profile avatar_url without avatar_type - Enforce connection-time IP validation and DNS pinning via custom SSRFProtectedBackend - Preserve full TLS verification (verify=True) with correct SNI hostname - Disable HTTP redirects in share card avatar fetcher - Add comprehensive regression test suite in tests/unit/ctf/test_avatar_ssrf.py
…d URL ports - Convert validate_avatar_url to an async non-blocking function using loop.getaddrinfo - Catch ValueError on urlparse and port conversion to return 400 Bad Request instead of 500 - Add dual-stack safe IP failover in SSRFProtectedBackend - Add tests verifying SNI server_hostname in TLS negotiation, dual-stack failover, and malformed URL handling
|
Hi @rohanbuilds-ai, thanks for working on this! Just a heads-up that #507 already covers #506 (I filed the issue and opened that PR back in May). I've just updated it to keep TLS verification on with IP pinning, using httpx's public Would you mind taking a look at #507? If you spot anything missing, suggestions there are very welcome. I'll leave it to the maintainers to decide how to go forward. |
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
Fixes #506.
This PR provides comprehensive SSRF hardening for the User Profile avatar update and share card fetch endpoints in
finbot/apps/ctf/routes/profile.pyandfinbot/apps/ctf/routes/share.py, addressing maintainer feedback from @c-thiam regarding IPv6 handling, multi-answer DNS, DNS rebinding / TOCTOU defenses, and preserving strict TLS verification (verify=True).Threat Model & Addressed Vulnerabilities
In
update_profile, avatar URL validation was previously gated onif request.avatar_type == "url":. If a client updatedavatar_urlwhile omittingavatar_type(None), validation was bypassed even when the stored profile already hadavatar_type == "url".Previous checks did not cover IPv6 loopback (
::1), link-local (fe80::/10), unique local (fc00::/7,fd00::/8), unspecified (::), cloud metadata (169.254.169.254), CGNAT (100.64.0.0/10), IPv4-mapped IPv6, or hostnames resolving to mixed public/private DNS records._fetch_avatar_b64previously usedfollow_redirects=Trueand had no connection-time IP pinning. A public URL could redirect to internal endpoints, or a DNS rebinding service with a short TTL could resolve to internal IPs at TCP connect time. Prior attempts (fix(security): resolve profile update validation bypass and SSRF #507) tried connecting directly to IP addresses withverify=False, which disabled TLS certificate verification.Malformed URLs (e.g. out-of-range ports like
:99999999or non-integer ports) raised unhandledValueErrorinsideurlparse, escaping the route handler as an unexpected HTTP 500 error instead of a controlled HTTP 400.Synchronous DNS resolution (
socket.getaddrinfo) directly on the event loop thread in async route handlers could freeze the worker process during slow DNS responses.Implementation Details
is_ip_allowed):127.0.0.0/8), RFC-1918 private subnets (10.0.0.0/8,172.16.0.0/12,192.168.0.0/16), link-local / cloud metadata (169.254.0.0/16), carrier-grade NAT (100.64.0.0/10), and0.0.0.0/8.::1/128), unique local (fc00::/7), link-local (fe80::/10), and unspecified (::/128).validate_avatar_url):ValueErrorinto HTTP 400 client errors.loop.getaddrinfo(...)in the thread pool executor, preventing event loop blocking.SSRFProtectedBackend):httpcore._backends.anyio.AnyIOBackend.connect_tcp(), asynchronously resolves the target hostname and fails closed if any address is prohibited or malformed.httpcore'sstart_tlscall for SNI and CA certificate validation (verify=True)._fetch_avatar_b64):validate_avatar_url.follow_redirects=False).make_ssrf_safe_transport().Verification & Test Coverage
A dedicated test suite has been added in
tests/unit/ctf/test_avatar_ssrf.py(30 test cases):avatar_type.http://,ftp://).SSRFProtectedBackend.server_hostnamein TLS negotiation retains the original domain name.Verified Test Results:
tests/unit/ctf/test_avatar_ssrf.py: 30 passed in 4.12stests/unit/ctf/: 57 passed, 1 skipped in 6.87stests/unit/apps/web/test_routes.py: 13 passed in 37.34sisort,black, andgit diff --check.Compatibility & Architectural Considerations
make_ssrf_safe_transport()configurestransport._pool._network_backend = SSRFProtectedBackend(). Whilehttpcore.AsyncConnectionPoolexposesnetwork_backendin its constructor,httpx.AsyncHTTPTransport.__init__does not currently expose it as a top-level parameter. This integration operates cleanly on the repository's pinnedhttpx 0.28.1andhttpcore 1.0.9while maintaining complete connection pooling and TLS verification pipelines.