CVE-2024-2029: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection') (CWE-78)
value: A command injection vulnerability exists in the `TranscriptEndpoint` of mudler/localai, specifically within the `audioToWav` function used for converting audio files to WAV format for transcription. The vulnerability arises due to the lack of sanitization of user-supplied filenames before passing them to ffmpeg via a shell command, allowing an attacker to execute arbitrary commands on the host system. Successful exploitation could lead to unauthorized access, data breaches, or other detrimental impacts, depending on the privileges of the process executing the code.
CWE description: The product constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component.
Published: 2024-04-10T17:15Z
Repository: https://github.com/mudler/localai
Language: Go
Files changed: backend/go/transcribe/transcript.go
Commit date: 2024-02-29 18:32:29 +0000
Commit message: Fix Command Injection Vulnerability (#1778)

* Added fix for command injection

* changed function name from sh to runCommand
Diff: diff --git a/backend/go/transcribe/transcript.go b/backend/go/transcribe/transcript.go
index dc331ca..fdfaa97 100644
--- a/backend/go/transcribe/transcript.go
+++ b/backend/go/transcribe/transcript.go
@@ -9,25 +9,25 @@ import (
 	"github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper"
 	"github.com/go-audio/wav"
 	"github.com/go-skynet/LocalAI/core/schema"
 )
 
-func sh(c string) (string, error) {
-	cmd := exec.Command("/bin/sh", "-c", c)
+func runCommand(command []string) (string, error) {
+	cmd := exec.Command(command[0], command[1:]...)
 	cmd.Env = os.Environ()
-	o, err := cmd.CombinedOutput()
-	return string(o), err
+	out, err := cmd.CombinedOutput()
+	return string(out), err
 }
 
-// AudioToWav converts audio to wav for transcribe. It bashes out to ffmpeg
+// AudioToWav converts audio to wav for transcribe.
 // TODO: use https://github.com/mccoyst/ogg?
 func audioToWav(src, dst string) error {
-	out, err := sh(fmt.Sprintf("ffmpeg -i %s -format s16le -ar 16000 -ac 1 -acodec pcm_s16le %s", src, dst))
+    command := []string{"ffmpeg", "-i", src, "-format", "s16le", "-ar", "16000", "-ac", "1", "-acodec", "pcm_s16le", dst}
+	out, err := runCommand(command)
 	if err != nil {
 		return fmt.Errorf("error: %w out: %s", err, out)
 	}
-
 	return nil
 }
 
 func Transcript(model whisper.Model, audiopath, language string, threads uint) (schema.Result, error) {
 	res := schema.Result{}

Vulnerable code: func sh(c string) (string, error) {
	cmd := exec.Command("/bin/sh", "-c", c)
	o, err := cmd.CombinedOutput()
	return string(o), err
// AudioToWav converts audio to wav for transcribe. It bashes out to ffmpeg
	out, err := sh(fmt.Sprintf("ffmpeg -i %s -format s16le -ar 16000 -ac 1 -acodec pcm_s16le %s", src, dst))

Fixed code: func runCommand(command []string) (string, error) {
	cmd := exec.Command(command[0], command[1:]...)
	out, err := cmd.CombinedOutput()
	return string(out), err
// AudioToWav converts audio to wav for transcribe.
    command := []string{"ffmpeg", "-i", src, "-format", "s16le", "-ar", "16000", "-ac", "1", "-acodec", "pcm_s16le", dst}
	out, err := runCommand(command)