Arbitrary Code Execution via Deserialization in huggingface/transformers
Description
The huggingface/transformers library is vulnerable to arbitrary code execution through deserialization of untrusted data within the load_repo_checkpoint() function of the TFPreTrainedModel() class. Attackers can execute arbitrary code and commands by crafting a malicious serialized payload, exploiting the use of pickle.load() on data from potentially untrusted sources. This vulnerability allows for remote code execution (RCE) by deceiving victims into loading a seemingly harmless checkpoint during a normal training process, thereby enabling attackers to execute arbitrary code on the targeted machine.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
CVE-2024-3568: Remote code execution through insecure pickle deserialization in Hugging Face Transformers' load_repo_checkpoint().
Root
Cause
The vulnerability resides in the load_repo_checkpoint() function of the TFPreTrainedModel() class within the Hugging Face Transformers library. This function uses pickle.load() to deserialize data from a checkpoint without sanitization, which allows arbitrary code execution when processing untrusted input [2][3].
Exploitation
An attacker can craft a malicious pickle payload disguised as a legitimate model checkpoint. If a victim loads this seemingly harmless checkpoint during training (for example, by fetching it from a remote repository), the pickle.load() call executes arbitrary code embedded in the payload [2]. The attack requires user interaction—the victim must be tricked into loading the malicious checkpoint—but does not require prior authentication or network access beyond what is needed to retrieve the file.
Impact
Successful exploitation grants the attacker full remote code execution (RCE) on the victim's machine. This can lead to data exfiltration, system compromise, or further lateral movement within the environment [2].
Mitigation
The vulnerability was addressed in commit 693667b, which removes the vulnerable load_repo_checkpoint() function entirely [3]. Users should update to a patched version of the Transformers library as soon as possible. No workaround exists other than updating, as the unsafe function has been deleted [1][3].
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
transformersPyPI | < 4.38.0 | 4.38.0 |
Affected products
2- huggingface/huggingface/transformersv5Range: unspecified
Patches
2693667b8ac81Remove dead TF loading code (#28926)
1 file changed · +0 −50
src/transformers/modeling_tf_utils.py+0 −50 modified@@ -32,7 +32,6 @@ import h5py import numpy as np import tensorflow as tf -from huggingface_hub import Repository, list_repo_files from packaging.version import parse from . import DataCollatorWithPadding, DefaultDataCollator @@ -1356,55 +1355,6 @@ def _save_checkpoint(self, checkpoint_dir, epoch): with open(extra_data_path, "wb") as f: pickle.dump(extra_data, f) - def load_repo_checkpoint(self, repo_path_or_name): - """ - Loads a saved checkpoint (model weights and optimizer state) from a repo. Returns the current epoch count when - the checkpoint was made. - - Args: - repo_path_or_name (`str`): - Can either be a repository name for your {object} in the Hub or a path to a local folder (in which case - the repository will have the name of that local folder). - - Returns: - `dict`: A dictionary of extra metadata from the checkpoint, most commonly an "epoch" count. - """ - if getattr(self, "optimizer", None) is None: - raise RuntimeError( - "Checkpoint loading failed as no optimizer is attached to the model. " - "This is most likely caused by the model not being compiled." - ) - if os.path.isdir(repo_path_or_name): - local_dir = repo_path_or_name - else: - # If this isn't a local path, check that the remote repo exists and has a checkpoint in it - repo_files = list_repo_files(repo_path_or_name) - for file in ("checkpoint/weights.h5", "checkpoint/extra_data.pickle"): - if file not in repo_files: - raise FileNotFoundError(f"Repo {repo_path_or_name} does not contain checkpoint file {file}!") - repo = Repository(repo_path_or_name.split("/")[-1], clone_from=repo_path_or_name) - local_dir = repo.local_dir - - # Now make sure the repo actually has a checkpoint in it. - checkpoint_dir = os.path.join(local_dir, "checkpoint") - weights_file = os.path.join(checkpoint_dir, "weights.h5") - if not os.path.isfile(weights_file): - raise FileNotFoundError(f"Could not find checkpoint file weights.h5 in repo {repo_path_or_name}!") - extra_data_file = os.path.join(checkpoint_dir, "extra_data.pickle") - if not os.path.isfile(extra_data_file): - raise FileNotFoundError(f"Could not find checkpoint file extra_data.pickle in repo {repo_path_or_name}!") - - # Assuming the repo is real and we got a checkpoint, load the weights and the optimizer state into the model. - # The optimizer state includes the iteration count, so learning rate schedules should resume as normal too. - self.load_weights(weights_file) - with open(extra_data_file, "rb") as f: - extra_data = pickle.load(f) - self.optimizer.set_weights(extra_data["optimizer_state"]) - - # Finally, return the epoch number from the checkpoint. This isn't a property of the model, so we can't - # set it directly, but the user can pass it to fit(). - return {"epoch": extra_data["epoch"]} - def prepare_tf_dataset( self, dataset: "datasets.Dataset", # noqa:F821
08ab54ada594Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4News mentions
0No linked articles in our index yet.