Validates registered redirect_uris for DCR are a secure schema with no fragments - #3206
Validates registered redirect_uris for DCR are a secure schema with no fragments#3206Varshith-Kali wants to merge 8 commits into
Conversation
There was a problem hiding this comment.
All reported issues were addressed across 3 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
… module The original implementation put validate_redirect_uri in routes.py, which caused a circular import: register.py imports from routes, and routes imports from other modules that import back. Moving the validation functions to a dedicated url_validators.py module breaks the cycle. - validate_redirect_uri now lives in url_validators.py alongside validate_issuer_url (previously in routes.py) - register.py imports from url_validators instead of routes - test_routes.py updated to import from url_validators - Ruff format fixes applied (single-line raise, double-quote match strings)
9eb6e29 to
fb893dd
Compare
The SDK intentionally accepts non-loopback HTTP redirect URIs per existing tests (test_a_non_loopback_http_redirect_uri_is_accepted). Narrow scope to only reject dangerous schemes (javascript:, data:, file:, etc.) and fragments, matching the SDK's existing policy.
There was a problem hiding this comment.
1 issue found across 2 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="tests/server/auth/test_routes.py">
<violation number="1" location="tests/server/auth/test_routes.py:102">
P1: validate_redirect_uri accepts http:// for any host, not just loopback. The docstring promises RFC 9700 HTTPS enforcement with loopback exception, but only non-HTTP(S) schemes are rejected — http://evil.com/cb passes. This exposes authorization codes to interception over plain HTTP for non-loopback redirect URIs.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| validate_redirect_uri(AnyHttpUrl("file:///etc/passwd")) | ||
|
|
||
|
|
||
| def test_validate_redirect_uri_http_non_loopback_allowed(): |
There was a problem hiding this comment.
P1: validate_redirect_uri accepts http:// for any host, not just loopback. The docstring promises RFC 9700 HTTPS enforcement with loopback exception, but only non-HTTP(S) schemes are rejected — http://evil.com/cb passes. This exposes authorization codes to interception over plain HTTP for non-loopback redirect URIs.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tests/server/auth/test_routes.py, line 102:
<comment>validate_redirect_uri accepts http:// for any host, not just loopback. The docstring promises RFC 9700 HTTPS enforcement with loopback exception, but only non-HTTP(S) schemes are rejected — http://evil.com/cb passes. This exposes authorization codes to interception over plain HTTP for non-loopback redirect URIs.</comment>
<file context>
@@ -99,9 +99,8 @@ def test_validate_redirect_uri_file_scheme_rejected():
-def test_validate_redirect_uri_http_non_loopback_rejected():
- with pytest.raises(ValueError, match="Redirect URI must use HTTPS"):
- validate_redirect_uri(AnyHttpUrl("http://evil.com/cb"))
+def test_validate_redirect_uri_http_non_loopback_allowed():
+ validate_redirect_uri(AnyHttpUrl("http://evil.com/cb"))
</file context>
AnyHttpUrl rejects non-HTTP schemes (javascript:, file:, etc.) at construction time, preventing validate_redirect_uri from ever being called. Switch to AnyUrl which accepts any scheme string, then reject unsafe schemes inside the validator. Also update error match pattern in tests from 'must use HTTPS' to 'must use an HTTP' to match the updated validator message.
There was a problem hiding this comment.
All reported issues were addressed across 2 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
|
Thanks for the review @cubic-dev-ai! Both issues found are now addressed:
|
@Varshith-Kali Looks good — both fixes are correctly reflected in the code I'm seeing. 1. 2. Non-loopback HTTP accepted — Also consistent with what's landed. The validator's scope is now narrow: reject only non-HTTP schemes and fragments. No new issues stand out in the current state. Tip: get faster answers by chatting with cubic’s review copilot in the review UI |
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/mcp/server/auth/url_validators.py">
<violation number="1" location="src/mcp/server/auth/url_validators.py:11">
P2: Non-HTTP(S) issuer URLs using a loopback host are now accepted. Since this signature admits `AnyUrl`, `javascript://localhost/...` and `file://localhost/...` bypass the current `scheme != "https" and host not in loopbacks` check. Keeping the loopback exception specific to the `http` scheme preserves the intended HTTPS-or-HTTP-loopback policy.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| from pydantic import AnyUrl | ||
|
|
||
|
|
||
| def validate_issuer_url(url: AnyUrl): |
There was a problem hiding this comment.
P2: Non-HTTP(S) issuer URLs using a loopback host are now accepted. Since this signature admits AnyUrl, javascript://localhost/... and file://localhost/... bypass the current scheme != "https" and host not in loopbacks check. Keeping the loopback exception specific to the http scheme preserves the intended HTTPS-or-HTTP-loopback policy.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/mcp/server/auth/url_validators.py, line 11:
<comment>Non-HTTP(S) issuer URLs using a loopback host are now accepted. Since this signature admits `AnyUrl`, `javascript://localhost/...` and `file://localhost/...` bypass the current `scheme != "https" and host not in loopbacks` check. Keeping the loopback exception specific to the `http` scheme preserves the intended HTTPS-or-HTTP-loopback policy.</comment>
<file context>
@@ -8,7 +8,7 @@
-def validate_issuer_url(url: AnyHttpUrl):
+def validate_issuer_url(url: AnyUrl):
"""Validate that the issuer URL meets OAuth 2.0 requirements.
</file context>
Fixes #2629.
Summary
Dynamic Client Registration currently accepts redirect_uris with unsafe schemes (javascript:, data:, file:, ftp:) and fragments without complaint. RFC 9700 .1.1 and RFC 7591 require HTTPS for redirect_uris and prohibit fragments.
Changes