ModelScan legacy PyTorch pickle scanner bypass PoC
This repository contains a benign reproduction for a ModelScan scanner/loader mismatch affecting legacy PyTorch serialization.
Summary
ModelScan 0.8.8 detects a benign eval reduce target as CRITICAL when it is
stored in zip-format PyTorch files.
The same payload saved with PyTorch legacy serialization
(torch.save(..., _use_new_zipfile_serialization=False)) is loadable with
explicit torch.load(..., weights_only=False), but ModelScan reports zero
issues for the legacy candidates across .pt, .pth, .ckpt, and .bin.
The PoC is intentionally benign. It returns only the static string
BENIGN_TORCH_MARKER.
Safety
The PoC does not:
- run shell commands;
- read credentials;
- perform network access;
- create persistence;
- modify external files;
- attempt stealth or evasion.
It demonstrates only scanner output and loader reachability.
Files
torch_legacy_pickle_probe.py- generates benign legacy and zip-format PyTorch controls;
- runs
torch.load()checks; - runs ModelScan JSON scans;
- prints one JSON line per sample.
Expected generated samples:
- legacy candidates:
legacy_direct.pt,legacy_direct.pth,legacy_direct.ckpt,legacy_direct.binlegacy_dict.*legacy_list.*
- zip-format controls:
zip_direct.pt,zip_direct.pth,zip_direct.ckpt,zip_direct.binzip_dict.*zip_list.*
Reproduce
python -m venv .venv
. .venv/bin/activate
pip install modelscan torch
python torch_legacy_pickle_probe.py corpus/torch_legacy_pickle_submission
Equivalent command from the local research repository:
.venv-modelscan/bin/python tools/torch_legacy_pickle_probe.py \
corpus/torch_legacy_pickle_submission \
--extensions .pt .pth .ckpt .bin \
--payload-kinds direct dict list
Expected Results
For every legacy candidate:
is_zip:falsetorch_load_weights_only_false.status:ok- marker resolves to
BENIGN_TORCH_MARKER - ModelScan
total_issues:0 - ModelScan
errors:[]
For every zip-format control:
is_zip:truetorch_load_weights_only_false.status:ok- marker resolves to
BENIGN_TORCH_MARKER - ModelScan reports one CRITICAL
evalissue indata.pkl
For both candidate and control samples:
- PyTorch 2.11.0 default loading rejects the PoC.
torch.load(..., weights_only=True)rejects the PoC.
Claim Boundary
This is a ModelScan scanner bypass / unsafe-global detection failure.
This PoC does not claim PyTorch default-load RCE, credential theft, data exfiltration, persistence, privilege escalation, authentication bypass, or Critical severity for the vulnerability as a whole.