fix: enable DNS rebinding protection by default#659
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a Ktor route-scoped DNS rebinding protection plugin and enables it by default for MCP HTTP/SSE endpoints, aligning behavior with the TypeScript SDK advisory.
Changes:
- Introduces
DnsRebindingProtection(RouteScopedPlugin) with default localhost allowlist and optional Origin allowlist. - Enables DNS rebinding protection by default in
Route.mcp,Application.mcp,mcpStreamableHttp, andmcpStatelessStreamableHttp; deprecates the old transport configuration flags. - Updates/extends JVM tests and conformance server setup to reflect the new defaults and host parsing behavior.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorRouteExtensionsTest.kt | Updates integration tests to explicitly disable protection where not under test. |
| kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorApplicationExtensionsTest.kt | Updates Application extension test to explicitly disable protection where not under test. |
| kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/DnsRebindingProtectionTest.kt | Adds new tests covering Host/Origin validation and extractHostname. |
| kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/StreamableHttpServerTransport.kt | Deprecates old DNS config fields and updates header validation to be port-agnostic. |
| kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorServer.kt | Adds new parameters to MCP helpers and enables protection by default via the new plugin. |
| kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/HostValidation.kt | New plugin + config + hostname extraction utility + default localhost allowlist. |
| kotlin-sdk-server/api/kotlin-sdk-server.api | Updates public API surface for new plugin/config and new MCP helper signatures. |
| conformance-test/src/main/kotlin/io/modelcontextprotocol/kotlin/sdk/conformance/ConformanceServer.kt | Removes redundant explicit DNS settings now covered by new defaults. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
e5l
left a comment
There was a problem hiding this comment.
lgtm, except comments. Please check comments before merging
There was a problem hiding this comment.
The DNS rebinding protection plugin architecture is secure and well-designed, but the PR should address three medium-severity gaps before merge: the deprecated validateHeaders() still defaults to no protection for direct transport usage, error responses reflect raw attacker-controlled header values, and there are no integration tests for the primary mcpStreamableHttp/mcpStatelessStreamableHttp entry points.
|
@kpavlov Why did you block the PR on yourself if you were not even listed as a reviewer? Also, I have already asked you to check AI reviews before posting them. We already have copilot for automated AI reviews |
|
@devcrocod, as I mentioned in the review, the response currently exposes raw request headers, which is a potential security risk — that’s why I stepped in. The AI-review also flags this and I agree it should be fixed. |
kpavlov
left a comment
There was a problem hiding this comment.
I’ve unblocked the PR to avoid slowing things down. The comments I left still highlight a potential issue with exposing raw request headers, so it would be good to address that in the next update.
This had already been pointed out before you reviewed it. I don't have a habit of merging PRs without approval or of ignoring comments. That is exactly why I did not merge it, even after receiving approval. Therefore, your intervention remains unclear to me. In addition, your own contribution is not entirely clear to me either: not all the comments seem substantive, and some of their wording appears to be AI-generated. That is why I have questions and would ask you not to limit your involvement to merely providing your github account for AI use |
I don't see any comment about headers exposure neither from Copilot nor from another reviewer. Maybe I am missing something. Could you please share the link to the comment where it was pointed out? |
8b7b725 to
61ed19b
Compare
61ed19b to
ad29817
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
ad29817 to
f4ac6fa
Compare
# Conflicts: # kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/StreamableHttpServerTransport.kt
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| * **Note:** this method does not perform DNS rebinding protection on its own. | ||
| * When using this transport outside the [mcpStreamableHttp] / [mcpStatelessStreamableHttp] | ||
| * DSL, install the [DnsRebindingProtection] plugin on your Ktor route | ||
| * (or apply equivalent middleware) to validate `Host` / `Origin` headers. |
| if (hostname == null || hostname !in allowedHostsLowercase) { | ||
| return "Invalid Host header: $hostHeader" | ||
| } |
Add
DnsRebindingProtectionKtor route-scoped plugin and enable it by default across all http transportsMotivation and Context
DNS rebinding protection was disabled by default (
enableDnsRebindingProtection = false), and sse endpoints (Route.mcp()) had zero protection. Same vulnerability as typescript sdk GHSA-w48q-cv73-mx4wHow Has This Been Tested?
all tests pass
Breaking Changes
Route.mcp(),Application.mcp()signatures changed (newenableDnsRebindingProtection,allowedHosts,allowedOriginsparams), binary incompatible on JVMenableDnsRebindingProtectiondefault changed fromfalsetotrueonmcpStreamableHttp/mcpStatelessStreamableHttplocalhost,127.0.0.1,[::1]— opt out withenableDnsRebindingProtection = falseOriginheader (non-browser clients)Configuration.enableDnsRebindingProtection,.allowedHosts,.allowedOriginsdeprecated in favor of the pluginTypes of changes
Checklist