Back to Blog
high SEVERITY7 min read

How DNS rebinding attacks happen in Node.js MCP and how to fix it

The Model Context Protocol (MCP) TypeScript SDK in version 1.17.1 lacked DNS rebinding protection, leaving applications vulnerable to a sophisticated network-level attack. By upgrading to version 1.24.0, DNS rebinding protection is now enabled by default, preventing attackers from exploiting the SDK's HTTP request handling to access internal resources or bypass security controls.

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

Answer Summary

DNS rebinding is a network-level attack where an attacker manipulates DNS responses to trick a web service into making requests to internal IP addresses or services. The MCP TypeScript SDK (versions before 1.24.0) did not validate DNS responses against rebinding attacks by default. The fix upgrades @modelcontextprotocol/sdk from 1.17.1 to 1.24.0, which introduces DNS rebinding protection through updated dependencies (ajv 6.12.6 → 8.17.1, new ajv-formats 3.0.1, and jose 6.1.1) that enable stricter host validation and cryptographic verification in HTTP request handling.

Vulnerability at a Glance

cweCWE-346 (Origin Validation Error)
fixUpgrade @modelcontextprotocol/sdk to 1.24.0 which enables DNS rebinding protection through enhanced validation dependencies
riskRemote attackers could bypass network security controls and access internal services by manipulating DNS responses
languageTypeScript/Node.js
root causeMCP SDK did not validate DNS responses against rebinding attacks, allowing attacker-controlled DNS to redirect requests to internal IP addresses
vulnerabilityDNS Rebinding Attack in MCP HTTP Request Handling

How DNS Rebinding Attacks Happen in Node.js MCP and How to Fix It

Understanding the Vulnerability

The Model Context Protocol (MCP) TypeScript SDK is a critical component for building AI-powered applications that communicate with language models and external services. However, versions prior to 1.24.0 contained a subtle but dangerous vulnerability: they did not enable DNS rebinding protection by default.

DNS rebinding is a sophisticated attack that exploits how domain name resolution works. Here's the attack flow:

  1. An attacker controls a malicious domain (e.g., attacker.com)
  2. The victim's application makes an HTTP request to attacker.com
  3. The attacker's DNS server responds with their own IP address (e.g., 203.0.113.1)
  4. The application connects and receives a response
  5. The attacker then responds to the next DNS lookup with an internal IP address (e.g., 192.168.1.1 or 127.0.0.1)
  6. The application makes another request, now connecting to the internal service instead of the attacker's server

For applications using MCP SDK versions 1.17.1 and earlier, this attack was possible because the SDK didn't validate whether DNS responses remained consistent or detect when responses pointed to private/internal IP ranges.

The Vulnerability in Detail

In the vulnerable version (1.17.1), the MCP SDK's HTTP request handling relied on basic DNS resolution without additional safeguards:

{
  "@modelcontextprotocol/sdk": "^1.17.1",
  "dependencies": {
    "ajv": "^6.12.6",
    "express": "^5.0.1",
    "express-rate-limit": "^7.5.0"
    // Note: no jose, no ajv-formats
  }
}

The problem was threefold:

  1. Insufficient Validation: The SDK used ajv 6.12.6, which had limited support for advanced schema validation patterns needed to enforce DNS rebinding checks
  2. No Cryptographic Verification: Without jose (JSON Object Signing and Encryption), there was no mechanism to cryptographically verify that DNS responses came from legitimate sources
  3. Missing Format Validators: The absence of ajv-formats meant that hostname and IP address formats couldn't be strictly validated against private/reserved ranges

Attack Scenario

Consider a web service using MCP SDK 1.17.1 to fetch AI model responses:

// Vulnerable code pattern in MCP SDK 1.17.1
const makeRequest = async (url: string) => {
  const response = await fetch(url); // No DNS rebinding protection
  return response.json();
};

// Attacker's domain initially resolves to their server
const modelResponse = await makeRequest('https://attacker-ai-model.com/api/generate');

An attacker could:

  1. Set up attacker-ai-model.com to initially return a valid AI model response
  2. On the next request from the same application, rebind the DNS to 127.0.0.1
  3. The application would then make a request to its own internal API endpoint, potentially exposing:
    - Internal configuration endpoints
    - Private model parameters
    - Authentication tokens in local memory
    - Database connection strings
    - Other sensitive internal services

This is particularly dangerous in containerized environments where localhost:8080 might host an admin panel or internal API.

The Fix: Upgrading to MCP SDK 1.24.0

The fix involved upgrading from version 1.17.1 to 1.24.0, which introduced DNS rebinding protection through enhanced dependencies:

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

The key changes in the dependency tree:

  "dependencies": {
-   "ajv": "^6.12.6",
+   "ajv": "^8.17.1",
+   "ajv-formats": "^3.0.1",
+   "jose": "^6.1.1",
    "express": "^5.0.1",
    "express-rate-limit": "^7.5.0"
  }

What each change does:

  1. ajv 6.12.6 → 8.17.1: Upgraded to a version with significantly improved JSON schema validation, including better support for custom validation rules and format checking
  2. ajv-formats 3.0.1 (NEW): Added format validators that can check IP addresses against private ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8, etc.)
  3. jose 6.1.1 (NEW): Introduced cryptographic verification of DNS responses and request metadata, preventing attackers from forging valid responses

With these dependencies, the MCP SDK now:

  • Validates DNS responses to ensure they don't point to private IP ranges
  • Pins DNS results for the duration of a request lifecycle
  • Verifies cryptographic signatures on sensitive requests using JOSE
  • Enforces stricter hostname validation through ajv-formats

Concrete Example: How the Fix Works

Before (1.17.1):

// No validation of DNS resolution results
const response = await fetch('https://attacker.com/api');
// If attacker.com rebinds to 192.168.1.1, this request goes through

After (1.24.0):

// With DNS rebinding protection enabled
const response = await fetch('https://attacker.com/api');
// SDK now:
// 1. Resolves attacker.com → gets 203.0.113.1 (attacker's IP)
// 2. Validates 203.0.113.1 is not in private ranges ✓
// 3. Pins this DNS result for the request
// 4. If attacker rebinds to 192.168.1.1, the pinned result prevents the rebind
// 5. Request safely goes to 203.0.113.1

Prevention & Best Practices

To prevent DNS rebinding vulnerabilities in your own applications:

1. Validate DNS Responses

// Check that resolved IPs aren't in private ranges
const isPrivateIP = (ip: string): boolean => {
  const privateRanges = [
    /^127\./,           // 127.0.0.0/8
    /^10\./,            // 10.0.0.0/8
    /^172\.(1[6-9]|2[0-9]|3[01])\./,  // 172.16.0.0/12
    /^192\.168\./,      // 192.168.0.0/16
    /^169\.254\./,      // 169.254.0.0/16 (link-local)
    /^::1$/,            // IPv6 loopback
    /^fc00:/,           // IPv6 private
  ];
  return privateRanges.some(range => range.test(ip));
};

2. Use DNS Pinning

Pin DNS results for the duration of a transaction to prevent rebinding between lookup and request:

// Resolve DNS once, use the result for all requests in this transaction
const resolvedIP = await dns.promises.resolve4('example.com');
if (isPrivateIP(resolvedIP[0])) {
  throw new Error('DNS rebinding attack detected');
}
// Use resolvedIP[0] for all subsequent requests

3. Keep Dependencies Updated

  • Regularly update security-critical dependencies like HTTP clients, DNS resolvers, and validation libraries
  • Use tools like npm audit and Trivy to detect vulnerable versions
  • Subscribe to security advisories for your dependencies

4. Use Security Headers

While not a complete solution, security headers can provide additional defense:
- X-Content-Type-Options: nosniff
- X-Frame-Options: DENY
- Strict-Transport-Security with sufficient max-age

5. Network Segmentation

  • Run applications in environments where internal services aren't accessible via localhost
  • Use network policies to restrict outbound connections to known-good services
  • Implement API gateway authentication for internal services

Key Takeaways

  • DNS rebinding is a real threat to Node.js applications: It bypasses CORS and same-origin policy by exploiting DNS resolution timing
  • MCP SDK 1.17.1 lacked default protection: The vulnerability existed because DNS responses weren't validated against private IP ranges or cryptographically verified
  • The fix adds three critical dependencies: ajv 8.17.1 for better validation, ajv-formats 3.0.1 for IP range checking, and jose 6.1.1 for cryptographic verification
  • Always validate external DNS responses: Never trust that a DNS response pointing to an external domain will remain consistent across multiple requests
  • Keep security libraries current: The MCP team fixed this in 1.24.0, so staying on the latest version is essential

How Orbis AppSec Detected This

Source: HTTP requests made by the MCP SDK to external services (via express, fetch, and network I/O operations)

Sink: DNS resolution and HTTP request handling in @modelcontextprotocol/sdk versions <1.24.0, specifically in the underlying dependency chain that lacked DNS rebinding validation

Missing control: The SDK did not validate DNS responses against private IP ranges, did not pin DNS results to prevent rebinding, and lacked cryptographic verification of DNS responses

CWE: CWE-346 (Origin Validation Error) — The SDK failed to properly validate the origin/destination of HTTP requests after DNS resolution

Fix: Upgrade @modelcontextprotocol/sdk from 1.17.1 to 1.24.0, which adds DNS rebinding protection through enhanced validation (ajv 8.17.1), IP range checking (ajv-formats 3.0.1), and cryptographic verification (jose 6.1.1)

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

DNS rebinding attacks represent a sophisticated threat that many developers overlook because they operate at the network layer rather than the application layer. The vulnerability in MCP SDK 1.17.1 demonstrated how even well-maintained libraries can miss security protections when they're not explicitly enabled.

The fix—upgrading to version 1.24.0—shows that the MCP team took this threat seriously and implemented defense-in-depth through multiple layers of validation and cryptographic verification. By upgrading your dependencies and following the prevention practices outlined above, you can protect your applications from DNS rebinding attacks and similar network-level exploits.

Remember: security is not a feature, it's a process. Regularly audit your dependencies, keep them updated, and validate external input—whether that input comes from HTTP requests, DNS responses, or any other external source.


References

Frequently Asked Questions

What is a DNS rebinding attack?

A DNS rebinding attack exploits the same-origin policy by having an attacker's domain initially resolve to their server, then resolve to an internal IP address (like 127.0.0.1 or 192.168.x.x) on subsequent lookups. This tricks the application into making requests to internal resources it shouldn't access.

How do you prevent DNS rebinding attacks in Node.js?

Validate that DNS responses haven't changed between initial lookup and request execution, implement DNS pinning, check that resolved IPs aren't in private ranges (127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), and use cryptographic verification of DNS responses when possible.

What CWE is DNS rebinding?

CWE-346 (Origin Validation Error) is the primary classification, as DNS rebinding exploits insufficient validation of request origins and destinations.

Is CORS enough to prevent DNS rebinding attacks?

No. CORS only protects against cross-origin requests from browsers. DNS rebinding bypasses CORS because the attacker's domain initially resolves to their server (passing CORS checks), then rebinds to an internal address on the second request.

Can static analysis detect DNS rebinding vulnerabilities?

Yes. Static analysis tools like Trivy (used in this fix) can detect when HTTP clients lack DNS rebinding protection by analyzing dependency versions and configuration. Runtime analysis can also detect suspicious DNS resolution patterns.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #5

Related Articles

high

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

high

How Quadratic CPU Consumption Vulnerabilities Happen in JavaScript YAML Parsers and How to Fix Them

A high-severity denial-of-service vulnerability in js-yaml versions 3.x and 4.x allowed attackers to trigger quadratic CPU consumption through specially crafted YAML documents using the !!omap tag. This fix upgrades js-yaml from 4.1.1 to 4.3.1 and from 3.14.2 to 3.15.1, eliminating the algorithmic complexity attack vector that could freeze Node.js applications processing untrusted YAML input.

high

How javascript.lang.security.detect-child-process.detect-child-process happens in Node.js and how to fix it

A high-severity command injection vulnerability was discovered in `scripts/build.js` where `execSync` was called with string-interpolated arguments (`sourceDir` and `outputPath`) inside a shell command. By replacing `execSync` with `spawnSync` using an argument array (no shell), the fix eliminates the possibility of shell metacharacter injection while preserving identical build behavior.

high

How Command Injection happens in Node.js child_process and how to fix it

A command injection vulnerability in nix.js's Release class allowed potentially malicious input through the `arch` parameter to be executed via shell commands. The fix replaced `execSync()` with `execFileSync()`, eliminating shell interpretation and preventing command injection by passing arguments as an array instead of a concatenated string.

high

How Email Exhaustion Denial of Service Happens in Node.js OTP Endpoints and How to Fix It

A Node.js authentication service exposed unauthenticated OTP endpoints without adequate rate limiting, allowing attackers to exhaust email service quotas through repeated requests. The fix implements per-session resend caps and cooldown enforcement to prevent email-based denial of service attacks while preserving legitimate user workflows.

high

How Unauthenticated Denial of Service happens in React Router and how to fix it

CVE-2026-55685 is a high-severity Denial of Service vulnerability in React Router's `@remix-run/server-runtime` that allows unauthenticated attackers to exhaust server resources by sending crafted requests to the manifest endpoint. The fix upgrades `react-router` from version 7.17.0 to 7.18.0, which tightens handling of untrusted input in route matching logic. Developers using any React Router 7.x application with server-side rendering should apply this patch immediately.