Security PoC β Remote Code Execution in NeuralForecast.load() via unsafe pickle
This repository is a proof-of-concept for a security vulnerability reported through
huntr (Model File Vulnerability program), published only as evidence for
responsible disclosure. The payload runs a harmless touch command. Do not load untrusted
NeuralForecast model directories on a machine you care about.
What this demonstrates
neuralforecast (Nixtla) restores a saved model with NeuralForecast.load(path). During load it
calls raw pickle.load on alias_to_model.pkl, dataset.pkl, and configuration.pkl
(neuralforecast/core.py, lines 2481 / 2501 / 2514) with no safeguard β no allowlist, no
weights_only, no safe_mode, no warning. So loading an untrusted model directory executes
attacker-chosen code. alias_to_model.pkl is unpickled before any checkpoint is parsed, so the
payload fires immediately.
Files
model_dir/alias_to_model.pklβ the malicious artifact. Its__reduce__runsos.system.model_dir/DummyModel_0.ckptβ empty file, only to pass the "at least one .ckpt" count guard.load_poc.pyβ builds the dir (or uses the bundled one) and triggers the sink via the public API.
Reproduce
pip install neuralforecast # 3.1.9
python load_poc.py /tmp/PWNED # creates /tmp/PWNED via os.system during load
ls -la /tmp/PWNED # file exists => arbitrary code executed
Expected:
[+] marker /tmp/PWNED exists = True
-rw-r--r-- 1 user group 0 ... /tmp/PWNED
Root cause (and fix)
neuralforecast/core.py, NeuralForecast.load:
with fsspec.open(f"{path}/alias_to_model.pkl", "rb") as f:
alias_to_model = pickle.load(f) # raw unpickle, no guard -> RCE
Fix: persist alias_to_model/configuration/dataset in a non-executable format (JSON / typed),
or gate unpickling behind an explicit default-off trust_remote=True with a loud warning; pass
weights_only=True to the checkpoint loader where feasible.
Disclosure
Reported via huntr. CWE-502 / CWE-94.