Arbitrary code execution via eval() of a third-party model pack's train.log field in the WebUI
还没有人认领这个 Issue。
评估
调研方向
阅读 change_info_ 中的 webui.py:1719-1726,以及 webui.py:2820-2822 中 ckpt_path2.change 的连接方式。运行 issue 的恶意 train.log 和负面控制复现,然后验证解析会拒绝可执行表达式,同时有效的 model-info 数据仍会更新选择器,且不会创建 canary 文件。
由索引模型根据 Issue 内容生成。
描述
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:
- 主要语言
- Python
- 星标
- 38.9k
- 派生
- 5.3k
- PR 合并指标
- 30 天内没有已合并 PR
环境准备
这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
RVC-Project/Retrieval-based-Voice-Conversion-WebUI 的其他 Issue
-
难度 2/5 1-3 小时 新手友好度 68/100
RVC-Project/Retrieval-based-Voice-Conversion-WebUI#2863 · 1 条评论 · 2 个 reaction ·
-
难度 2/5 1-3 小时 新手友好度 68/100
RVC-Project/Retrieval-based-Voice-Conversion-WebUI#2862 · 2 条评论 ·
-
难度 2/5 1-3 小时 新手友好度 78/100
-
难度 1/5 1 小时以内 新手友好度 85/100
RVC-Project/Retrieval-based-Voice-Conversion-WebUI#2831 · 1 条评论 ·
-
audio field未关闭
难度 2/5 1-3 小时 新手友好度 65/100
查看 RVC-Project/Retrieval-based-Voice-Conversion-WebUI 的全部 Issue
相似的 Issue
-
type-bug
难度 2/5 1-3 小时 新手友好度 72/100
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 78/100
维护者通常 1 天内回复
-
push_gh-pages fails on master branch on forks可能已有人在做 关联的 PR 仍在进行中或已合并。 未关闭good first issue infrastructure
难度 2/5 1-3 小时 新手友好度 76/100
kuznia-rdzeni/coreblocks#1135 ·
-
good first issue server
难度 2/5 1-3 小时 新手友好度 85/100
维护者通常 1 天内回复
-
documentation priority: high
难度 2/5 1-3 小时 新手友好度 78/100
a-lex-s/mealie-telegram-bot#54 ·
维护者通常 1 天内回复