Downloads · 30 days
0
EnigmaConsultant/huntr-poc-pickle-dupcd-datapkl-desync
huntr-poc-pickle-dupcd-datapkl-desync is a machine learning model from EnigmaConsultant. Use it for the machine learning task on the model card, and read the license before you ship it in a product. The card lists the license as mit.
Targets (all current PyPI releases, verified 2026-07-20): picklescan 1.0.5, modelscan 0.8.8, fickling 0.1.12 Real loader: torch.load(..., weightsonly=False) — PyTorch 2.13.0+cpu (caffe2::serialize::PyTorchStreamReader…
Downloads · 30 days
0
Access
Public
Updated Jul 20, 2026
Repo size
4.9 KB
Likes
0
Public
Click a slice to open those files.
.md5.8 KB · 32%
From the Hugging Face model README
data.pkl central-directory record — an HONEST-ZIP container desync that bypasses picklescan 1.0.5, modelscan 0.8.8 AND fickling 0.1.12 while torch.load executesTargets (all current PyPI releases, verified 2026-07-20):
picklescan 1.0.5, modelscan 0.8.8, fickling 0.1.12
Real loader: torch.load(..., weights_only=False) — PyTorch 2.13.0+cpu (caffe2::serialize::PyTorchStreamReader / miniz)
Class: CWE-436 Interpretation Conflict — ZIP container member-name resolution divergence → scanner evasion → RCE on model load
Impact: A .pt/.bin PyTorch checkpoint that all three scanners certify CLEAN runs attacker os.system(...) the moment a victim runs the ordinary torch.load(weights_only=False).
zipfile) on a duplicate member nameA new-format PyTorch checkpoint is a ZIP whose pickle lives in the record archive/data.pkl.
The PoC ZIP contains two central-directory records both named archive/data.pkl:
index 0 archive/data.pkl <- MALICIOUS pickle (__reduce__ -> os.system)
index 1 archive/.format_version
...
index 6 archive/data.pkl <- BENIGN pickle
EOCD: total-entries = 7 (matches the 7 physical central-dir records — see below)
data.pkl via mz_zip_reader_locate_file, which returns the
FIRST matching record → reads index 0 (MALICIOUS) → executes it.zipfile builds a NameToInfo dict by iterating every central-directory
record with unconditional NameToInfo[name] = info, so a duplicate name is last-wins →
zip.open("archive/data.pkl") returns index 6 (BENIGN).All three scanners walk ZIP members with stdlib zipfile (picklescan/relaxed_zipfile.py,
modelscan.py:_iterate_models, fickling.loader.scan_zip_archive), so every one of them scans
the benign member and never sees the malicious data.pkl that miniz loads.
The EOCD "total entries" field equals the number of physical central-directory records (7 == 7),
no offsets are patched, no CRCs are faked, and every record parses cleanly. It is produced by two
plain ZipFile.writestr("archive/data.pkl", ...) calls. A scanner that validates the EOCD
entry-count, CRCs, or offsets still accepts it and is still bypassed — the desync is purely in how
a duplicate member name is resolved.
| File | torch.load(weights_only=False) | picklescan 1.0.5 | modelscan 0.8.8 | fickling 0.1.12 |
|---|---|---|---|---|
dupcd_mal.pt (two data.pkl, mal-first) | RCE — marker written | Infected: 0 CLEAN (exit 0) | No issues found 🎉 (exit 0) | LIKELY_SAFE |
control_mal.pt (single mal data.pkl) | RCE | Infected: 1 DETECTED | CRITICAL: 1 (exit 1) | LIKELY_OVERTLY_MALICIOUS |
The control proves the payload is trivially detectable by every scanner in isolation — only the
duplicate-record ordering hides it. A reversed build (benign-first / mal-last) flips every verdict
(scanners flag it, torch.load runs the benign member), proving first-vs-last resolution is the
exact lever.
# loader side (needs torch)
python build_poc.py # writes dupcd_mal.pt / dupcd_mal.bin / control_mal.pt
python verify.py # honest-count check + zipfile-vs-torch.load divergence + RCE marker
# scanner side (picklescan==1.0.5 fickling==0.1.12 modelscan==0.8.8, Python 3.10-3.12)
python -m picklescan -p dupcd_mal.pt # Infected files: 0 (CLEAN)
modelscan -p dupcd_mal.pt # No issues found! 🎉
python -c "from fickling.loader import scan_zip_archive as s; print(s('dupcd_mal.pt'))" # LIKELY_SAFE
Captured runs are in scan_results.txt.
weights_only=False (PyTorch >= 2.6 defaults to True, an orthogonal mitigation). This is the same
precondition the entire picklescan/modelscan/fickling threat model assumes, and it remains pervasive
in training-resume, from_pretrained, and legacy checkpoint call sites.
zipfile.is_zipfile router; this one is a member-resolution
divergence inside a fully valid ZIP that every router agrees is a torch zip..pt zipfile-vs-miniz differential
(pt-zip-differential). This finding is materially stronger and corrects it:
zipfile still
last-wins, so the divergence persists without any forgery. This defeats count-validating
scanners the forged variant would not.zipfile too and are
equally bypassed, demonstrated here end-to-end.Reject any archive containing duplicate member names (both scanners and torch.load should refuse
a checkpoint with two data.pkl records), or resolve member names with the same first-match rule
miniz uses so the scanned bytes equal the loaded bytes.