Jul 31, 2026·6 min read·55 visits
A DNS-rebinding flaw in the MCP Ruby SDK (< 0.23.0) allows malicious sites to bypass the browser Same-Origin Policy and run arbitrary local tools.
A critical vulnerability (CVE-2026-63118) in the Model Context Protocol (MCP) Ruby SDK allows attackers to execute arbitrary JSON-RPC commands and exfiltrate sensitive local data from an MCP server bound to the local loopback interface. This is achieved through DNS-rebinding and cross-origin request execution due to missing validation of the HTTP Host and Origin headers in the StreamableHTTPTransport component.
The Model Context Protocol (MCP) Ruby SDK provides infrastructure for building local and remote AI assistant tools. A core component of this library is the StreamableHTTPTransport class, which implements a Rack-compatible HTTP server designed to handle incoming JSON-RPC requests. This transport layer allows client applications to communicate with local MCP servers, initiating sessions and invoking functional components.
Prior to version 0.23.0, the StreamableHTTPTransport component lacked host and origin verification routines on incoming HTTP requests. Because developers typically deploy MCP servers locally on loopback interfaces, the lack of host and origin restrictions exposed the server to severe security risks. Specifically, malicious web applications running in a user's browser could interact directly with the locally bound server.
This structural flaw is classified under CWE-346 (Origin Validation Error) and CWE-350 (Reliance on Reverse DNS Resolution for a Security-Critical Action). It allows attackers to orchestrate DNS-rebinding attacks or direct cross-origin request execution. The vulnerability is tracked as CVE-2026-63118 and carries a CVSS v4 base score of 6.9, reflecting high subsequent confidentiality impact on the host system.
The root cause of CVE-2026-63118 lies in the unconditional acceptance of HTTP traffic by the StreamableHTTPTransport server. When a web server processes requests, it typically relies on the web browser's Same-Origin Policy (SOP) to isolate cross-origin domains. However, SOP relies on the assumption that a domain name resolves consistently to a single IP address during a session. This assumption is invalidated by DNS rebinding.
In a DNS-rebinding scenario, an attacker configures a custom nameserver for a domain they control. When the victim accesses this domain, the nameserver responds with the attacker's actual server IP but sets a very short Time-To-Live (TTL). Once the browser caches or expires the DNS record, the attacker's nameserver points subsequent resolutions of the exact same domain to the loopback address 127.0.0.1.
Because the browser associates the domain with the previous origin, it allows scripts to issue requests to the rebound address, thinking it is still contacting the attacker's server. Because the vulnerable SDK did not inspect the incoming Host header (which still contained the attacker's domain) or the Origin header, the local MCP server executed the incoming JSON-RPC commands and returned the results to the browser, bypassing SOP.
The vulnerability was addressed in commit ba543083a7594e7892b29464b89091816446ff7a by implementing a validation routine on every request handled by StreamableHTTPTransport. This validation is integrated directly into the handle_request method, intercepting execution before any HTTP methods are parsed.
Below is the comparison of the request handling logic before and after the patch:
# Vulnerable implementation (prior to v0.23.0)
def handle_request(request)
case request.env["REQUEST_METHOD"]
when "POST"
handle_post(request)
# ... processed unconditionally
end
end# Patched implementation (v0.23.0)
def handle_request(request)
rebinding_error = validate_dns_rebinding(request)
return rebinding_error if rebinding_error
case request.env["REQUEST_METHOD"]
# ... normal execution after validation passes
end
endThe validate_dns_rebinding method relies on two subsidiary checks: validate_host and validate_origin. If @dns_rebinding_protection is enabled, the server validates that the HTTP_HOST matches an allowed host (by default, 127.0.0.1, ::1, or localhost) and that the HTTP_ORIGIN matches the current host or an allowed origin list. If either check fails, the server responds with a 403 Forbidden status and an INVALID_REQUEST JSON-RPC error. This patch is highly complete because it applies strict secure-by-default behavior while preserving compatibility for complex reverse proxy setups.
Exploitation of CVE-2026-63118 relies on user interaction and a targeted DNS infrastructure. The attacker must first lure a victim who is currently running a local MCP server to visit a malicious website under the attacker's control. The interaction flows according to the following communication sequence:
Once the browser is directed to 127.0.0.1, the malicious JavaScript payload issues a POST request to initialize an MCP session. The request does not trigger CORS warnings because the browser believes it is communicating with the original evil.attacker.com origin:
POST / HTTP/1.1
Host: evil.attacker.com:9292
Content-Type: application/json
{"jsonrpc": "2.0", "method": "initialize", "id": "init_id", "params": {"protocolVersion": "2025-11-25", "capabilities": {}, "clientInfo": {"name": "evil-client", "version": "1.0"}}}After retrieving the session identifier, the script invokes sensitive tools registered on the local server, such as system command runners or filesystem tools. The response containing secret tokens or system command outputs is then returned to the JavaScript execution context and transmitted back to the attacker.
The impact of successful exploitation is severe and depends largely on the level of system access granted to the local MCP server. Since MCP is designed to allow local AI clients to run local operations, these servers are frequently configured with highly privileged tools. Common capabilities include direct terminal command execution, filesystem write capabilities, and localized database access.
An attacker who successfully exploits CVE-2026-63118 gains full access to these local APIs. They can execute system utilities, read sensitive SSH keys, access active cloud provider credentials, or install persistent backdoors on the host machine. Because the attacker operates from within the victim's browser session, the local firewall and network perimeter controls are completely bypassed.
According to the CVSS v4 vector, the vulnerability is rated as 6.9 (Medium). Although the vulnerability itself does not guarantee immediate system compromise, the subsequent system confidentiality impact is high (SC:H). The attack requirements are present (AT:P) because the attacker must host a functional DNS-rebinding infrastructure, but the user interaction is minimal (UI:A), requiring only a single website visit.
To resolve CVE-2026-63118, developers must upgrade the mcp gem to version 0.23.0 or higher. This release integrates host and origin checking by default, preventing unauthenticated clients from invoking API functions. The gem can be updated by declaring gem 'mcp', '>= 0.23.0' in the Gemfile and running bundle update mcp.
If the server is deployed behind an upstream reverse proxy that already filters the Host and Origin headers, protection can be configured as follows:
transport = MCP::Server::Transports::StreamableHTTPTransport.new(
server,
allowed_hosts: ["mcp.example.com"],
allowed_origins: ["https://app.example.com"]
)If upgrading is not immediately possible, teams must implement alternative mitigation patterns. A manual Rack middleware can be written to drop requests containing unfamiliar Host headers. Additionally, developers must ensure that the local server is bound strictly to 127.0.0.1 or ::1 rather than the wild wildcard 0.0.0.0, reducing exposure from nearby hosts on local area networks.
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:A/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
mcp modelcontextprotocol | < 0.23.0 | v0.23.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-346, CWE-350 |
| Attack Vector | Network (AV:N) |
| CVSS Score | 6.9 (Medium) |
| Exploit Status | PoC Available |
| Affected Component | StreamableHTTPTransport |
| Fixed Version | v0.23.0 |
| CISA KEV Status | Not Listed |
The software does not properly validate the origin of a request, letting unauthorized domains make state-modifying or sensitive requests.
Nginx UI versions 2.5.0 through 2.5.10 contain an uncontrolled resource consumption vulnerability in the node authentication handler. Unauthenticated remote attackers can exhaust host disk storage and I/O resources by submitting large HTTP request bodies to node-signature endpoints prior to cryptographic signature validation.
Vikunja versions 2.3.0 through 2.6.0 contain an insufficient session expiration vulnerability (CWE-613) within the WebSocket authentication handler. Although Vikunja enforces server-side session tracking and revocation for REST API routes, the WebSocket handshake handler validates cryptographic JWT signatures without querying the database session state. Consequently, revoked JWT tokens can establish new real-time WebSocket connections, and existing connections persist after session revocation.
A cross-tenant boundary breach vulnerability in Vikunja allows an authenticated user to trigger global task position recalculations across all tenant instances by creating a saved filter with an empty filter string payload.
An access revocation flaw in Vikunja allows removed collaborators to retain outbound webhooks and link shares created prior to revocation, enabling persistent exfiltration of sensitive task data.
Vikunja v2.6.0 contains a permission inheritance regression in pkg/models/project_access.go where explicit down-restrictions on sub-projects are overridden by higher parent project permissions due to MAX aggregation across project tree nodes.
An authorization bypass vulnerability in Vikunja's link share deletion handlers allows project members with Write privileges to delete Admin-tier link shares. The handler passes an unpopulated struct to the authorization check, causing the permission evaluation to fall back to default Write permissions instead of requiring Admin privileges.