fix: add DNS-rebinding protection to _OriginCheckMiddleware#6227
Open
XananasX7 wants to merge 1 commit into
Open
fix: add DNS-rebinding protection to _OriginCheckMiddleware#6227XananasX7 wants to merge 1 commit into
XananasX7 wants to merge 1 commit into
Conversation
When the ADK web server is bound to a loopback address (127.0.0.1 / ::1 / localhost) and no explicit --allow-origins list has been configured, a DNS-rebinding attack is possible: 1. Attacker serves a page at evil.com. 2. Victim opens http://evil.com (or is redirected there). 3. Attacker changes the DNS record for evil.com to resolve to 127.0.0.1. 4. The attacker's JS issues a cross-origin POST to http://evil.com:8000/run (which now hits the local ADK server). 5. The browser sends Origin: http://evil.com and Host: evil.com. 6. _get_request_origin returns http://evil.com (derived from Host). 7. _is_request_origin_allowed sees origin == request_origin => ALLOW. 8. The attacker can call /run, read session data, etc. Fix: introduce _is_loopback_address() and, when the ASGI server tuple shows the server is actually bound to a loopback address, require that the incoming Origin is also a loopback address before falling through to the same-origin (Host-derived) comparison. This mirrors the DNS-rebinding protection added to the MCP go-sdk SSEHandler (DisableLocalhostProtection option). Adds 21 unit tests covering: - _is_loopback_address() for all common forms - DNS-rebinding attack scenarios (IPv4, named localhost, IPv6) - Legitimate same-origin requests remain allowed - Explicit --allow-origins list overrides the guard - Non-loopback servers are unaffected Fixes: DNS-rebinding attack against adk web local development server
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
This PR adds DNS-rebinding protection to the
_OriginCheckMiddlewarein the ADK web server.Vulnerability
When the ADK development server is bound to a loopback address (
127.0.0.1/::1/localhost) — the default — and no explicit--allow-originslist is configured, a DNS-rebinding attack allows a malicious web page to make authenticated cross-origin requests to the local server.Attack Steps
evil.comand serves a malicious page there.http://evil.com(or is redirected there).evil.com's DNS to point to127.0.0.1.POSTtohttp://evil.com:8000/run.Origin: http://evil.comandHost: evil.com._get_request_origin()derives the "request origin" from theHostheader (http://evil.com) and_is_request_origin_allowed()seesorigin == request_origin→ ALLOW./runwith arbitrary prompts, read session history, exfiltrate memory, etc.Fix
Added two helpers:
_is_loopback_address(host)— correctly identifies127.x.x.x,localhost,::1,[::1], and all port-suffixed variants viaipaddress.ip_address().is_loopback._get_server_host(scope)— reads the actual bound address from the ASGIservertuple (set by uvicorn, not attacker-controlled).In
_is_request_origin_allowed(), when the server is on loopback and no explicit allow-list is configured, the function now additionally requires that theOriginheader also resolves to a loopback host — blocking the DNS-rebinding attack regardless of what theHostheader says.Legitimate same-origin requests (browser at
http://localhost:8000→ server at127.0.0.1:8000) continue to work. Explicit--allow-originsconfiguration overrides the guard as before.Tests
21 new unit tests in
tests/unittests/cli/test_dns_rebinding_protection.pycovering:_is_loopback_addressfor all host formats (IPv4, IPv6, bracketed, with/without port, hostnames)localhost, and IPv6::1--allow-originsallowlist still overrides the guard0.0.0.0) are unaffectedImpact
Without this fix, any web page a developer visits while running
adk webcan:POST /runSeverity: Medium (requires the victim to visit a malicious page while the dev server is running; limited to the local machine).