[GH-ISSUE #2807] Arbitrary code execution via unsafe torch.load of a downloaded .pth voice model (weights_only not set) #2012

Open
opened 2026-10-20 10:13:54 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @geo-chen on GitHub (Jun 12, 2026).
Original GitHub issue: https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/issues/2807

Summary

RVC loads a selected .pth voice model with torch.load(...) and does not pass weights_only=True. The project pins torch below 2.6, where the default is weights_only=False, so loading a model performs full pickle deserialization. RVC voice models are routinely downloaded and shared, so a malicious .pth placed in the weights directory and selected in the inference dropdown executes arbitrary code on the victim's machine the moment it is loaded. Confirmed against the real load path: a crafted .pth ran a command during unpickling.

Details

infer/modules/vc/modules.py (~line 100 to 103):

person = f'{os.getenv("weight_root")}/{sid}'
...
self.cpt = torch.load(person, map_location="cpu")   # no weights_only -> pickle on torch < 2.6

sid is the inference voice-model dropdown value (sid0, infer-web.py ~line 819), wired sid0.change(fn=vc.get_vc, ...) (infer-web.py ~lines 1107 to 1109) and also exposed as a Gradio api_name. The dropdown lists *.pth files in weight_root (assets/weights), exactly where users drop downloaded voice models. The same unsafe torch.load (no weights_only) appears across the repo (uvr5 infer/lib/uvr5_pack/... vr.py ~33/214, rmvpe.py ~544, process_ckpt.py, train.py pretrained loads); the inference dropdown is the directly user-facing path.

Loading a shared/downloaded voice model is the normal, advertised operation of RVC (the ecosystem revolves around trading .pth models), so a malicious model is the recognized untrusted-model code-execution boundary.

PoC

Impact

A user who downloads a malicious RVC voice model and selects it for inference executes attacker code with their privileges, with no further interaction. If the WebUI is run with --listen / share and an attacker can place a file in the weights directory, the exposure increases.

Remediation

Load with torch.load(person, map_location="cpu", weights_only=True) and read cpt["weight"] as a plain state dict; if non-tensor metadata is needed, allowlist the required globals via torch.serialization.add_safe_globals. Apply the same fix to every torch.load in the repo. Consider migrating model artifacts to safetensors.

Originally created by @geo-chen on GitHub (Jun 12, 2026). Original GitHub issue: https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/issues/2807 ### Summary RVC loads a selected `.pth` voice model with `torch.load(...)` and does not pass `weights_only=True`. The project pins torch below 2.6, where the default is `weights_only=False`, so loading a model performs full pickle deserialization. RVC voice models are routinely downloaded and shared, so a malicious `.pth` placed in the weights directory and selected in the inference dropdown executes arbitrary code on the victim's machine the moment it is loaded. Confirmed against the real load path: a crafted `.pth` ran a command during unpickling. ### Details `infer/modules/vc/modules.py` (~line 100 to 103): ```python person = f'{os.getenv("weight_root")}/{sid}' ... self.cpt = torch.load(person, map_location="cpu") # no weights_only -> pickle on torch < 2.6 ``` `sid` is the inference voice-model dropdown value (`sid0`, `infer-web.py` ~line 819), wired `sid0.change(fn=vc.get_vc, ...)` (`infer-web.py` ~lines 1107 to 1109) and also exposed as a Gradio `api_name`. The dropdown lists `*.pth` files in `weight_root` (`assets/weights`), exactly where users drop downloaded voice models. The same unsafe `torch.load` (no `weights_only`) appears across the repo (uvr5 `infer/lib/uvr5_pack/...` `vr.py` ~33/214, `rmvpe.py` ~544, `process_ckpt.py`, `train.py` pretrained loads); the inference dropdown is the directly user-facing path. Loading a shared/downloaded voice model is the normal, advertised operation of RVC (the ecosystem revolves around trading `.pth` models), so a malicious model is the recognized untrusted-model code-execution boundary. ### PoC <available upon request> ### Impact A user who downloads a malicious RVC voice model and selects it for inference executes attacker code with their privileges, with no further interaction. If the WebUI is run with `--listen` / share and an attacker can place a file in the weights directory, the exposure increases. ### Remediation Load with `torch.load(person, map_location="cpu", weights_only=True)` and read `cpt["weight"]` as a plain state dict; if non-tensor metadata is needed, allowlist the required globals via `torch.serialization.add_safe_globals`. Apply the same fix to every `torch.load` in the repo. Consider migrating model artifacts to safetensors.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
RVC-Project/Retrieval-based-Voice-Conversion-WebUI#2012
No description provided.