CVE-2026-31232 Overview
CVE-2026-31232 is an insecure deserialization vulnerability [CWE-502] in the CosyVoice project, an open-source text-to-speech framework maintained by FunAudioLLM. The flaw affects all code up to commit 6e01309e01bc93bbeb83bdd996b1182a81aaf11e. The model loading routine invokes torch.load() without the weights_only=True argument, permitting Python Pickle deserialization of arbitrary objects from .pt files. An attacker who can convince a victim to load a malicious model directory through the CosyVoice web interface achieves remote code execution on the host system.
Critical Impact
Loading an attacker-supplied .pt model file through the --model_dir argument executes embedded pickle payloads, granting remote code execution under the privileges of the CosyVoice process.
Affected Products
- CosyVoice project (FunAudioLLM) through commit 6e01309e01bc93bbeb83bdd996b1182a81aaf11e
- Deployments exposing the CosyVoice web interface with user-controllable --model_dir
- Any downstream fork inheriting the vulnerable torch.load() call
Discovery Timeline
- 2026-05-12 - CVE CVE-2026-31232 published to NVD
- 2026-05-14 - Last updated in NVD database
Technical Details for CVE-2026-31232
Vulnerability Analysis
CosyVoice loads PyTorch model checkpoints from a directory supplied via the --model_dir command-line argument. The implementation calls torch.load() on each .pt file without setting weights_only=True. PyTorch's default deserialization path uses Python's pickle module, which invokes arbitrary callables encoded in the serialized stream through the __reduce__ protocol.
An attacker crafts a .pt file containing a pickle payload that resolves to functions such as os.system, subprocess.Popen, or builtins.exec. When CosyVoice's web interface loads the attacker's directory, the payload runs in-process. The user interaction required is limited to selecting or pointing the application at the malicious directory, which lowers the barrier in shared, multi-tenant, or research environments where models are routinely shared.
Root Cause
The root cause is the absence of the weights_only=True parameter in torch.load() calls within the model loading code path. PyTorch introduced weights_only specifically to restrict deserialization to tensor data and reject arbitrary global references. Without it, the loader treats every .pt file as fully trusted, executing whatever callables the pickle stream contains.
Attack Vector
The attack vector is network-adjacent through the web interface. An attacker hosts a malicious model directory containing one or more .pt files with embedded pickle gadgets. The attacker then induces a victim to load that directory through social engineering, a typosquatted model repository, or a compromised model hub. On load, the embedded payload executes commands on the victim's host, enabling credential theft, persistence, lateral movement, or model poisoning.
The vulnerability mechanism follows the standard Python pickle gadget pattern: a malicious class implements __reduce__ to return a tuple of a callable and its arguments, which pickle.load() then invokes during deserialization. See the GitHub PoC Repository and the Notion CVE Analysis for technical details.
Detection Methods for CVE-2026-31232
Indicators of Compromise
- Unexpected child processes spawned by the Python interpreter running CosyVoice, particularly sh, bash, cmd.exe, powershell.exe, or curl/wget invocations.
- .pt files in model_dir paths whose size or structure does not match legitimate CosyVoice checkpoints.
- Outbound network connections from the CosyVoice host to unfamiliar domains immediately after a model load event.
- New cron jobs, systemd units, or startup entries created shortly after CosyVoice activity.
Detection Strategies
- Statically scan .pt files with tools such as pickletools or picklescan to flag GLOBAL opcodes referencing dangerous modules like os, subprocess, builtins, or posix.
- Hook or audit torch.load() calls in CosyVoice deployments to log invocations missing the weights_only=True argument.
- Monitor process ancestry to detect shell or interpreter execution descending from the CosyVoice Python process.
Monitoring Recommendations
- Forward CosyVoice application logs and host process telemetry to a centralized analytics platform for correlation with file write and network connection events.
- Alert on first-seen .pt files appearing in directories referenced by --model_dir outside of approved deployment workflows.
- Track outbound connections from machine-learning workload hosts and baseline expected destinations.
How to Mitigate CVE-2026-31232
Immediate Actions Required
- Restrict the CosyVoice web interface to trusted operators and remove any path that allows untrusted users to control --model_dir.
- Load only .pt files originating from verified, integrity-checked sources; reject models distributed over untrusted channels.
- Patch the model loader to pass weights_only=True to every torch.load() invocation, or switch to the safetensors format for checkpoint storage.
- Run CosyVoice under a low-privilege service account, ideally inside a container or sandbox with no outbound internet access by default.
Patch Information
At publication, no upstream fix commit is referenced in the NVD entry. Operators should track the CosyVoice repository for a corrective commit and apply the weights_only=True change locally in the interim. The Notion CVE Analysis provides additional remediation context.
Workarounds
- Replace torch.load(path) with torch.load(path, weights_only=True) in all CosyVoice model loading code paths.
- Migrate stored checkpoints from .pt (pickle) to safetensors, which does not execute code on load.
- Enforce SHA-256 allowlists for model files and reject any .pt whose hash is not pre-approved.
- Deploy seccomp, AppArmor, or SELinux profiles that block process execution and outbound networking from the CosyVoice service.
# Configuration example: validate models before loading
sha256sum -c approved_models.sha256 || { echo 'Model integrity check failed'; exit 1; }
# Run CosyVoice under a restricted user inside a network-isolated container
docker run --rm \
--user 10001:10001 \
--read-only \
--network none \
--cap-drop=ALL \
-v /srv/cosyvoice/models:/models:ro \
cosyvoice:patched --model_dir /models
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.


