Arbitrary code execution via eval() of a third-party model pack's train.log field in the WebUI
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 78/100
Línea de trabajo
Lee webui.py:1719-1726 en change_info_ y la conexión de ckpt_path2.change en webui.py:2820-2822. Ejecuta las reproducciones de train.log maliciosa y de control negativo del issue, y verifica después que el análisis rechaza expresiones ejecutables mientras los datos válidos de model-info siguen actualizando los selectores sin crear el archivo canary.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
1. Summary
RVC WebUI wires the change event of the model-path textbox to change_info_ (webui.py:2821). change_info_ reads the sidecar file train.log shipped next to the selected model, takes the last tab-separated field of the first line, and passes it straight to eval() (webui.py:1719-1726). Model packs usually come from third-party sharing (cloud drives, model sites), so this train.log is attacker-controlled untrusted input: with a completely benign .pth, a single line of log text is enough to execute arbitrary Python code with WebUI process privileges on the victim's machine.
2. Affected version / environment
Repository: RVC-Project/Retrieval-based-Voice-Conversion-WebUI; verification anchor: commit 81eed5e (webui.py:1715-1731 change_info_; webui.py:2821 .change wiring); latest release: tag 2.3.260718 and the current main branch (checked 2026-09-30) still contain the same code; history: tag 2.2.231006 (2023-10) already had the same eval in infer-web.py:754-761, so the flaw is at least ~2 years old; PoC environment: Docker official python:3.11-slim image (Python 3.11.16) with the project's own CPU dependency list requirments_cpu_py312.txt (gradio 3.14.0; torch 2.4.1+cpu); the WebUI listens on 0.0.0.0:7897 by default.
3. Steps to reproduce
- Build a model pack evil_model/ containing two files: G_23333.pth is a normal, benign small checkpoint (generated with torch.save, byte-identical to the negative control); the first line of train.log follows the project's own log format "%(asctime)s\t%(name)s\t%(levelname)s\t%(message)s" with the last field (the message slot) replaced by the Python expression (import('pathlib').Path('/out/pwned_by_rvc_train_log_eval').write_text('MBE2E-CANARY-rvc-train-log-eval-v1\n', encoding='utf-8'), {'sample_rate': '48k', 'if_f0': 1, 'version': 'v2'})[1], which first writes a canary file and then returns the model-info dict, so the UI update completes normally without any error.
- Start the WebUI: python webui.py --pycmd python3 --port 7897
- Fire the same event a real user triggers: put the path evil_model/G_23333.pth into the "Path to Model" textbox of the checkpoint-extraction section (the .change event invokes change_info_); in the PoC the project's own Gradio queue API is used (/queue/join WebSocket, same protocol as the product frontend), submitting that path with fn_index pointing at the .change listener.
- Observe the server filesystem: /out/pwned_by_rvc_train_log_eval now exists with content "MBE2E-CANARY-rvc-train-log-eval-v1", while the UI shows no anomaly at all.
- Negative control: same directory layout and byte-identical .pth, but with the last train.log field replaced by the plain dict literal {'sample_rate': '48k', 'if_f0': 1, 'version': 'v2'}; repeat step 3 — it returns 48k/1/v2 and produces no file.
4. Expected behavior / Actual behavior
Expected: train.log is untrusted data carried inside a third-party model pack; parsing its field to prefill the sample-rate/if_f0/version selectors must never execute any code from it.
Actual: the field content is evaluated by eval(); the attacker's expression runs with WebUI process privileges, and because the payload returns a legitimate info dict the UI updates silently — no error, no warning.
5. Impact
- Full arbitrary code execution with WebUI process privileges: file read/exfiltration, persistence, weight replacement, all possible.
- The payload hides in "log text" while the .pth stays clean, so weight-based scanning and user intuition (people only look at the weights) both miss it; the expression returns a normal dict, so nothing is surfaced to the UI.
- The trigger (selecting/pasting a model path in the WebUI) is the unavoidable step of loading community models; no training, no GPU, no extra interaction required.
6. Suggested fix
Replace the eval() at webui.py:1719 with a constrained parser: prefer ast.literal_eval(info_str), which accepts literals only and rejects any call or name lookup; treat parse failures as "no train.log info" (fall back to the UI defaults) instead of swallowing them into a traceback; the cleaner long-term option is a JSON convention (json.dumps on the writer side), fully dropping Python literal evaluation. Also consider warning the user when a model path with a sidecar train.log is loaded for the first time.
7. Additional context
- Vulnerable code (webui.py:1719-1726, commit 81eed5e):
info = eval(
read_text(
ckpt_path.replace(os.path.basename(ckpt_path), "train.log")
)
.strip("\n")
.split("\n")[0]
.split("\t")[-1]
)
sr, f0 = info["sample_rate"], info["if_f0"]
- Event wiring (webui.py:2820-2822):
ckpt_path2.change(
change_info_, [ckpt_path2], [sr__, if_f0__, version_1]
)
link:
- Lenguaje dominante
- Python
- Estrellas
- 38.9k
- Forks
- 5.3k
- Métricas de merge de PR
- Sin PR fusionados en 30 d
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de RVC-Project/Retrieval-based-Voice-Conversion-WebUI
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
RVC-Project/Retrieval-based-Voice-Conversion-WebUI#2863 · 1 comentario · 2 reacciones ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
RVC-Project/Retrieval-based-Voice-Conversion-WebUI#2862 · 2 comentarios ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
-
add git clone into READMEAbierto
Dificultad 1/5 Menos de una hora Aptitud para principiantes 85/100
RVC-Project/Retrieval-based-Voice-Conversion-WebUI#2831 · 1 comentario ·
-
audio fieldAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
Todos los issues de RVC-Project/Retrieval-based-Voice-Conversion-WebUI
Issues similares
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
conda-forge/conda-forge-bot#7025 ·
Los mantenedores suelen responder en 1 día
-
chore(ci): publish.yml's release-job comment counts the hand-created Releases as all of themAbiertoarea:ci
Dificultad 1/5 Menos de una hora Aptitud para principiantes 74/100
catincloud-labs/dagster-dex#149 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
home-assistant/core#188424 ·
Los mantenedores suelen responder en 1 día
-
Review backlog (docs-currency): README 'CI run' link lands on a run whose overall badge is cancelledAbiertoagent/reviewer needs-kind needs-triage
Dificultad 2/5 1-3 horas Aptitud para principiantes 63/100
projectbluefin/utah#880 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
LSan reports obj_gen leak on post-parse usage() exits (aarch64)Posiblemente ocupada Un pull request vinculado a esta issue está abierto o ya se fusionó. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
redis/memtier_benchmark#850 ·
Los mantenedores suelen responder en 1 día