SWivid / SWivid/F5-TTS

[Vulnerability] OS command injection in finetune_gradio.py start_training() via shell=True

Open
#1,306 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Python
Stars
15.3k
Forks
2.2k
PR merge metrics
No merged PRs in 30d

Description

Checks
  • This template is only for bug reports, usage problems go with 'Help Wanted'.
  • I have thoroughly reviewed the project documentation but couldn't find information to solve my problem.
  • I have searched for existing issues, including closed ones, and couldn't find a solution.
  • I am using English to submit this issue to facilitate community communication.
Environment Details
  • OS: Linux container
  • User privileges: root inside the container
  • Python: 3.11
  • Environment manager: Miniconda
  • Conda environment: f5-tts
  • F5-TTS installation: local editable installation from the cloned repository
  • F5-TTS source path:
/hdd2/ul7ear/F5-TTS
  • Affected source file:
/hdd2/ul7ear/F5-TTS/src/f5_tts/train/finetune_gradio.py
  • Gradio application URL:
http://127.0.0.1:7861/
  • Environment information
Python: 3.11.15 (main, Jun 11 2026, 15:20:16) [GCC 14.3.0]
Python executable: /hdd2/ul7ear/miniconda3/envs/f5-tts/bin/python
Gradio: 5.49.1
PyTorch: 2.13.0+cu130
PyTorch CUDA: 13.0
CUDA available: False
F5-TTS module: None
git -C /hdd2/ul7ear/F5-TTS rev-parse HEAD
git -C /hdd2/ul7ear/F5-TTS status --short
91f499635cb4f8b8a926e83f1839f5338bc2ef87
Steps to Reproduce

The start_training() function constructs an accelerate launch command by concatenating values received from the Gradio interface into a single string.

For example, the pretrained checkpoint value is added as follows:

if file_checkpoint_train != "":
    cmd += f' --pretrain "{file_checkpoint_train}"'

The command is then executed through an operating-system shell:

training_process = subprocess.Popen(cmd, shell=True)

The streaming branch also uses:

training_process = subprocess.Popen(
    cmd,
    shell=True,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    text=True,
    bufsize=1,
    env=env,
)

Because POSIX shells evaluate command substitution expressions such as $(...) inside double quotes, the checkpoint-path field can execute an operating-system command.

1. Create a test project

In the Gradio interface, create a project named:

security_poc

This creates a project similar to:

security_poc_pinyin

Create the raw.arrow file required by start_training():

touch /hdd2/ul7ear/F5-TTS/data/security_poc_pinyin/raw.arrow

The file does not need to contain a valid dataset for this reproduction. The shell command is evaluated before the training script processes the dataset or checkpoint.

2. Remove any previous marker
rm -f /tmp/f5tts_cmd_injection_poc
3. Open the Train Model tab

Select the following project:

security_poc_pinyin

Enable Finetune.

4. Enter the following value in “Path to the Pretrained Checkpoint”
$(printf 'F5TTS_POC\n' > /tmp/f5tts_cmd_injection_poc)

This payload only creates a local marker file under /tmp. It does not access secrets, create a network connection, or modify application files.

Image
5. Click “Start Training”

The application prints a command similar to:

accelerate launch "/hdd2/ul7e


ar/F5-TTS/src/f5_tts/train/finetune_cli.py" --exp_name F5TTS_v1_Base --learning_rate 1e-05 --batch_size_per_gpu 3200 --batch_size_type frame --max_samples 64 --grad_accumulation_steps 1 --max_grad_norm 1 --epochs 1 --num_warmup_updates 10 --save_per_updates 10 --keep_last_n_checkpoints 0 --last_per_updates 10 --dataset_name security_poc --finetune --pretrain "$(printf F5TTS_POC > /tmp/f5tts_cmd_injection_poc)" --tokenizer pinyin --log_samples
6. Check the marker file
ls -l /tmp/f5tts_cmd_injection_poc
cat /tmp/f5tts_cmd_injection_poc

Observed contents:

F5TTS_POC
Image
✔️ Expected Behavior

Values entered into file-path fields should be passed to the training process as literal command-line arguments.

Shell syntax such as the following should not be interpreted or executed:

$()
;
&&
|
>
`
❌ Actual Behavior

The checkpoint-path value is concatenated into a shell command string and executed using:

subprocess.Popen(cmd, shell=True)

As a result, command substitution contained in the checkpoint-path field is evaluated by the operating-system shell.

The non-destructive reproduction successfully created:

/tmp/f5tts_cmd_injection_poc

This confirms arbitrary command execution with the privileges of the F5-TTS Gradio process.

In the reproduced environment, the process was running as root inside a container. Therefore, the injected command executed with root privileges inside that container.

The security impact depends on deployment:

  • On a trusted localhost-only deployment, an attacker requires access to the local Gradio interface or API.
  • If the application is bound to 0.0.0.0, shared through a Gradio public link, published from a container, or exposed through an unauthenticated reverse proxy, this may become unauthenticated remote command execution.
  • An attacker could potentially read or modify accessible model files, datasets, environment variables, API tokens, and host-mounted files.
  • Available CPU and GPU resources could also be abused.

Likely classification:

CWE-78: Improper Neutralization of Special Elements used in an OS Command

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/f5_tts/train/finetune_gradio.py at start_training(), especially the command construction and both subprocess.Popen calls shown in the report. Trace the values received from the Gradio interface and ensure path fields reach the training process as literal arguments rather than shell syntax. Done means inputs containing $(), ;, &&, |, >, or backticks are not executed while training still starts with the intended arguments.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
security
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.