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 NO_PROXY bypass via crafted URL happens in Node.js axios and how to fix it

A high-severity vulnerability (CVE-2026-42043) in axios versions prior to 1.15.1 allowed attackers to bypass NO_PROXY environment variable restrictions using specially crafted URLs. This meant HTTP requests intended to stay internal could be routed through an attacker-controlled proxy, potentially exposing sensitive data. The fix upgrades axios to version 1.15.1, which correctly validates URLs against NO_PROXY rules.

high

How shell injection via `${{` variable interpolation happens in GitHub Actions and how to fix it

A high-severity shell injection vulnerability was discovered in `.github/commaSplitter/action.yaml` where unsanitized user input was directly interpolated into a bash `run:` step using `${{ inputs.input }}`. An attacker could craft a malicious input string to escape the shell command and execute arbitrary code on the GitHub Actions runner, potentially stealing secrets and source code. The fix introduces an intermediate environment variable to safely pass the input without shell interpretation.

high

How missing Dependabot cooldown configuration happens in GitHub Actions and how to fix it

A high-severity vulnerability was discovered in the `.github/dependabot.yml` configuration file where no cooldown period was set for dependency updates. This exposed the Node.js library and its downstream consumers to potentially malicious or unstable packages immediately after publication. The fix adds a 7-day cooldown period to all package ecosystem entries, providing a critical safety buffer before accepting newly published package versions.

high

How command injection happens in Ruby backticks and how to fix it

A Jekyll plugin used unsafe Ruby backticks to execute a `git log` command with an unescaped file path, creating a command injection vulnerability. By switching to `Open3.capture2()` with argument array syntax, the fix prevents shell interpretation and eliminates the attack surface entirely.

high

How NO_PROXY bypass via crafted URL happens in Node.js axios and how to fix it

A high-severity vulnerability (CVE-2026-42043) was discovered in axios versions prior to 1.15.1, allowing attackers to bypass NO_PROXY configurations using specially crafted URLs. This could expose sensitive internal traffic to proxy servers, potentially leaking credentials or internal data. The fix upgrades axios to version 1.15.1, which properly validates URLs before applying proxy exclusion rules.