Coordinated Disclosure Timeline

Summary

GPT-SoVITS is vulnerable to multiple command injections.

Project

RVC-Boss/GPT-SoVITS

Tested Version

20250228v3

Details

Issue 1: command injection in webui.py open_slice function (GHSL-2025-045)

slice_opt_root and slice-inp-path takes user input, which is passed to the open_slice function, which concatenates the user input into a command and runs it on the server, leading to arbitrary command execution.

def open_slice(inp,opt_root,threshold,min_length,min_interval,hop_size,max_sil_kept,_max,alpha,n_parts):
    global ps_slice
    inp = my_utils.clean_path(inp)
    opt_root = my_utils.clean_path(opt_root)
    check_for_existance([inp])
    if(os.path.exists(inp)==False):
        yield i18n("输入路径不存在"), {"__type__": "update", "visible": True}, {"__type__": "update", "visible": False}, {"__type__": "update"}, {"__type__": "update"}, {"__type__": "update"}
        return
    if os.path.isfile(inp):n_parts=1
    elif os.path.isdir(inp):pass
    else:
        yield i18n("输入路径存在但不可用"), {"__type__": "update", "visible": True}, {"__type__": "update", "visible": False}, {"__type__": "update"}, {"__type__": "update"}, {"__type__": "update"}
        return
    if (ps_slice == []):
        for i_part in range(n_parts):
            cmd = '"%s" tools/slice_audio.py "%s" "%s" %s %s %s %s %s %s %s %s %s''' % (python_exec,inp, opt_root, threshold, min_length, min_interval, hop_size, max_sil_kept, _max, alpha, i_part, n_parts)
            print(cmd)
            p = Popen(cmd, shell=True)

Impact

This issue may lead to arbitrary command execution.

CWEs

Issue 2: command injection in webui.py open_denoise function (GHSL-2025-046)

denoise_inp_dir and denoise_opt_dir take user input, which is passed to the open_denoise function, which concatenates the user input into a command and runs it on the server, leading to arbitrary command execution.

def open_denoise(denoise_inp_dir, denoise_opt_dir):
    global p_denoise
    if(p_denoise==None):
        denoise_inp_dir=my_utils.clean_path(denoise_inp_dir)
        denoise_opt_dir=my_utils.clean_path(denoise_opt_dir)
        check_for_existance([denoise_inp_dir])
        cmd = '"%s" tools/cmd-denoise.py -i "%s" -o "%s" -p %s'%(python_exec,denoise_inp_dir,denoise_opt_dir,"float16"if is_half==True else "float32")

        yield process_info(process_name_denoise, "opened"), {"__type__": "update", "visible": False}, {"__type__": "update", "visible": True}, {"__type__": "update"}, {"__type__": "update"}
        print(cmd)
        p_denoise = Popen(cmd, shell=True)

Impact

This issue may lead to arbitrary command execution.

Issue 3: command injection in webui.py open_asr function (GHSL-2025-047)

asr_inp_dir (and a number of other variables) takes user input, which is passed to the open_asr function, which concatenates the user input into a command and runs it on the server, leading to arbitrary command execution.

def open_asr(asr_inp_dir, asr_opt_dir, asr_model, asr_model_size, asr_lang, asr_precision):
    global p_asr
    if p_asr is None:
        asr_inp_dir=my_utils.clean_path(asr_inp_dir)
        asr_opt_dir=my_utils.clean_path(asr_opt_dir)
        check_for_existance([asr_inp_dir])
        cmd = f'"{python_exec}" tools/asr/{asr_dict[asr_model]["path"]}'
        cmd += f' -i "{asr_inp_dir}"'
        cmd += f' -o "{asr_opt_dir}"'
        cmd += f' -s {asr_model_size}'
        cmd += f' -l {asr_lang}'
        cmd += f" -p {asr_precision}"
        output_file_name = os.path.basename(asr_inp_dir)
        output_folder = asr_opt_dir or "output/asr_opt"
        output_file_path = os.path.abspath(f'{output_folder}/{output_file_name}.list')
        yield process_info(process_name_asr, "opened"), {"__type__": "update", "visible": False}, {"__type__": "update", "visible": True}, {"__type__": "update"}, {"__type__": "update"}, {"__type__": "update"}
        print(cmd)
        p_asr = Popen(cmd, shell=True)

Impact

This issue may lead to arbitrary command execution.

Issue 4: command injection in webui.py change_label function (GHSL-2025-048)

path_list takes user input, which is passed to the change_label function, which concatenates the user input into a command and runs it on the server, leading to arbitrary command execution.

def change_label(path_list):
    global p_label
    if p_label is None:
        check_for_existance([path_list])
        path_list = my_utils.clean_path(path_list)
        cmd = '"%s" tools/subfix_webui.py --load_list "%s" --webui_port %s --is_share %s'%(python_exec,path_list,webui_port_subfix,is_share)
        yield process_info(process_name_subfix, "opened"), {'__type__':'update','visible':False}, {'__type__':'update','visible':True}
        print(cmd)
        p_label = Popen(cmd, shell=True)

Impact

This issue may lead to arbitrary command execution.

Credit

These issues were discovered and reported by GHSL team member @sylwia-budzynska (Sylwia Budzynska).

Contact

You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2025-045, GHSL-2025-046, GHSL-2025-047, or GHSL-2025-048 in any communication regarding these issues.