-
Notifications
You must be signed in to change notification settings - Fork 17
feat: add DNS rebinding protection conformance tests #115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Add a new server conformance scenario to verify that localhost MCP servers properly validate Host headers to prevent DNS rebinding attacks. Checks: - localhost-host-rebinding-rejected: Verifies server returns 403 for non-localhost Host headers (e.g., evil.example.com) - localhost-host-valid-accepted: Verifies server accepts requests with valid localhost Host headers Also updates the everything-server example to use createMcpExpressApp() which includes DNS rebinding protection by default. Closes #103 Co-Authored-By: Claude <noreply@anthropic.com>
Add a minimal MCP server that intentionally omits DNS rebinding protection to serve as a negative test case. This server is expected to FAIL the dns-rebinding-protection scenario. Also update README to document the negative test case. Co-Authored-By: Claude <noreply@anthropic.com>
Update the DNS rebinding protection test to accept any 4xx status code as a valid rejection response, not just 403. This accommodates different HTTP semantics: - 403 Forbidden: Per MCP spec - 421 Misdirected Request: RFC 7540 (semantically correct for DNS rebinding) - Other 4xx: Implementation-specific error codes
commit: |
| EventId, | ||
| StreamId | ||
| } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; | ||
| import { createMcpExpressApp } from '@modelcontextprotocol/sdk/server/express.js'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: this example is going to get deleted in a follow-up PR to make the typescript-sdk example the source of truth. updating it in place for now.
- Simplify negative test server (remove event store, sessions) - Update spec reference URL to security_best_practices - Clarify scope: localhost servers without HTTPS/auth - DRY up checks.push using spread operator - Fix valid host check to require 2xx response
…tion - Send both Host and Origin headers in test requests so servers checking either header will pass the conformance test - Add second spec reference for Origin check (transports#security-warning) - Update descriptions to mention both Host and Origin headers - Fix protocol version to 2025-11-25 - Remove unnecessary 'as const' type assertions
| hostHeader: validHost, | ||
| originHeader: `http://${validHost}`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should actually be testing these separately? Otherwise we don't know whether the server will reject both a bad host and a bad origin, we only know that it will reject either:
- both
- only header
- only origin
but not which specifically
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's intentional, we want either protection to be valid. Checking host or origin will prevent the attack.
Summary
Add conformance tests to verify localhost MCP servers properly validate Host headers to prevent DNS rebinding attacks.
Closes #103
Changes
New scenario:
dns-rebinding-protectionTwo checks:
localhost-host-rebinding-rejected: Server returns 4xx for non-localhost Host headers (e.g.,Host: evil.example.com)localhost-host-valid-accepted: Server accepts valid localhost Host headersImplementation details
undicifor making HTTP requests with custom Host headers (native fetch doesn't allow this)Additional changes
everything-serverexample to usecreateMcpExpressApp()for DNS rebinding protectionno-dns-rebinding-protection.tsthat intentionally omits protectionTesting
Verified against:
createMcpExpressApp())Related