CVE-2023-49795 (Python, published 2023-12-11T19:15Z)
Description: value: MindsDB connects artificial intelligence models to real time data. Versions prior to 23.11.4.1 contain a server-side request forgery vulnerability in `file.py`. This can lead to limited information disclosure. Users should use MindsDB's `staging` branch or v23.11.4.1, which contain a fix for the issue.

Severity: nan (CVSS v3 base score: 5.3)
Weakness: CWE-918 \u2014 Server-Side Request Forgery (SSRF)
The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.
Repository: https://github.com/mindsdb/mindsdb
Files changed:
mindsdb/api/http/namespaces/file.py
mindsdb/integrations/handlers/llama_index_handler/llama_index_handler.py
mindsdb/integrations/handlers/web_handler/web_handler.py
mindsdb/utilities/security.py
Commit message: fixes:
- SSRF
- arbitrary file write
https://github.com/mindsdb/mindsdb_private/issues/341


Vulnerable code:
            data["file"] = file.file_name.decode()
            data["file"] = data["name"]
        original_file_name = data.get("original_file_name")
            reader = SimpleWebPageReader(html_to_text=True).load_data([args['using']['source_url_link']])
                        f'url can be url = "someurl", you can also crawl multiple sites, as follows: url IN ("url1", "url2", ..)')
            

Fixed code:
from mindsdb.utilities.security import is_private_url, clear_filename
            data["file"] = clear_filename(file.file_name.decode())
            data["file"] = clear_filename(data["name"])
            if is_cloud and is_private_url(url):
                return http_error(
                    400, f'URL is private: {url}'
                )

        original_file_name = clear_filename(data.get("original_file_name"))
from mindsdb.utilities.security import is_private_url
            url = args['using']['source_url_link']
            config = Config()
            is_cloud = config.get("cloud", False)
            if is_cloud and is_private_url(url):
                raise Exception(f'URL is private: {url}')

            reader = SimpleWebPageReader(html_to_text=True).load_data([url])
from mindsdb.utilities.security import is_private_url
from mindsdb.utilities.config import Config
                        f'url can be url = "someurl", you can also crawl multiple sites, as follows:'
                        f' url IN ("url1", "url2", ..)'
                    )

        config = Config()
        is_cloud = config.get("cloud", False)
        if is_cloud:
            urls = [
                url
                for url in urls
                if not is_private_url(url)
            ]

from urllib.parse import urlparse
import socket
import ipaddress


def is_private_url(url: str):
    """
    Raises exception if url is private

    :param url: url to check
    """

    hostname = urlparse(url).hostname
    if not hostname:
        # Unable find hostname in url
        return True
    ip = socket.gethostbyname(hostname)
    return ipaddress.ip_address(ip).is_private


def clear_filename(filename: str):
    """
    Removes path symbols from filename which could be used for path injection
    :param s:
    :return:
    """

    if not filename:
        return filename
    badchars = '\\/:*?\"<>|'
    for c in badchars:
        filename = filename.replace(c, '')
    return filename