NIST deprecates RSA-2048 from 2030. Find every one of them before attackers do.
🐍 PyPI
Not in CISA KEV

fickling's `platform` module subprocess invocation evades `check_safety()` with `LIKELY_SAFE`GHSA-5cxw-w2xg-2m8h

Fix: trailofbits/fickling@351ed4d

GHSA-5cxw-w2xg-2m8h is a remote code execution vulnerability in fickling. A fix is available for fickling — see the affected versions and patch details below.

Published
Updated
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Mar 14, 2026 · OSV.dev, FIRST.org (EPSS)

Real-World Exposure

1 pkg affected
🐍fickling

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.

Description

Our assessment

We added platform to the blocklist of unsafe modules (https://github.com/trailofbits/fickling/commit/351ed4d4242b447c0ffd550bb66b40695f3f9975).

It was not possible to inject extra arguments to file without first monkey-patching platform._follow_symlinks with the pickle, as it always returns an absolute path. We independently hardened it with https://github.com/trailofbits/fickling/commit/b9e690c5a57ee9cd341de947fc6151959f4ae359 to reduce the risk of obtaining direct module references while evading detection.

https://github.com/python/cpython/blob/6d1e9ceed3e70ebc39953f5ad4f20702ffa32119/Lib/platform.py#L687-L695

target = _follow_symlinks(target)
# "file" output is locale dependent: force the usage of the C locale
# to get deterministic behavior.
env = dict(os.environ, LC_ALL='C')
try:
    # -b: do not prepend filenames to output lines (brief mode)
    output = subprocess.check_output(['file', '-b', target],
                                     stderr=subprocess.DEVNULL,
                                     env=env)

Original report

Summary

A crafted pickle invoking platform._syscmd_file, platform.architecture, or platform.libc_ver passes check_safety() with Severity.LIKELY_SAFE and zero findings. During fickling.loads(), these functions invoke subprocess.check_output with attacker-controlled arguments or read arbitrary files from disk.

Clarification: The subprocess call uses a list argument (['file', '-b', target]), not shell=True, so the attacker controls the file path argument to the file command, not the command itself. The impact is subprocess invocation with attacker-controlled arguments and information disclosure (file type probing), not arbitrary command injection.

Affected versions

<= 0.1.9 (verified on upstream HEAD as of 2026-03-04)

Non-duplication check against published Fickling GHSAs

No published advisory covers platform module false-negative bypass. This follows the same structural pattern as GHSA-5hwf-rc88-82xm (missing modules in UNSAFE_IMPORTS) but covers a distinct set of functions.

Root cause

  1. platform not in UNSAFE_IMPORTS denylist.
  2. OvertlyBadEvals skips calls imported from stdlib modules.
  3. UnusedVariables heuristic neutralized by making call result appear used (SETITEMS path).

Reproduction (clean upstream)

from unittest.mock import patch
import fickling
import fickling.fickle as op
from fickling.fickle import Pickled
from fickling.analysis import check_safety

pickled = Pickled([
    op.Proto.create(4),
    op.ShortBinUnicode('platform'),
    op.ShortBinUnicode('_syscmd_file'),
    op.StackGlobal(),
    op.ShortBinUnicode('/etc/passwd'),
    op.TupleOne(),
    op.Reduce(),
    op.Memoize(),
    op.EmptyDict(),
    op.ShortBinUnicode('init'),
    op.ShortBinUnicode('x'),
    op.SetItem(),
    op.Mark(),
    op.ShortBinUnicode('trace'),
    op.BinGet(0),
    op.SetItems(),
    op.Stop(),
])

results = check_safety(pickled)
print(results.severity.name, len(results.results))  # LIKELY_SAFE 0

with patch('subprocess.check_output', return_value=b'ASCII text') as mock_sub:
    fickling.loads(pickled.dumps())
    print('subprocess called?', mock_sub.called)       # True
    print('args:', mock_sub.call_args[0])               # (['file', '-b', '/etc/passwd'],)

Additional affected functions (same pattern):

  • platform.architecture('/etc/passwd') — calls _syscmd_file internally
  • platform.libc_ver('/etc/passwd') — opens and reads arbitrary file contents

Minimal patch diff

--- a/fickling/fickle.py
+++ b/fickling/fickle.py
@@
+        "platform",

Validation after patch

  • Same PoC flips to LIKELY_OVERTLY_MALICIOUS
  • fickling.loads raises UnsafeFileError
  • subprocess.check_output is not called

Impact

  • False-negative verdict: check_safety() returns LIKELY_SAFE with zero findings for a pickle that invokes a subprocess with attacker-controlled arguments.
  • Subprocess invocation: platform._syscmd_file calls subprocess.check_output(['file', '-b', target]) where target is attacker-controlled. The file command reads file headers and returns type information, enabling file existence and type probing.
  • File read: platform.libc_ver opens and reads chunks of an attacker-specified file path.

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐍PyPIficklingall versions0.1.10pip install --upgrade 'fickling==0.1.10'

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for fickling, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update fickling to 0.1.10 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-5cxw-w2xg-2m8h is resolved across your whole dependency graph.

  3. Workarounds

    Stop passing untrusted input into the interpreter or shell: call the affected binary with an argument array rather than a composed command string, reject anything outside a strict allowlist of expected values, and run the component under an account that cannot reach beyond the work it legitimately does.

Frequently Asked Questions

# Our assessment We added `platform` to the blocklist of unsafe modules (https://github.com/trailofbits/fickling/commit/351ed4d4242b447c0ffd550bb66b40695f3f9975). It was not possible to inject extra arguments to `file` without first monkey-patching `platform._follow_symlinks` with the pickle, as it always returns an absolute path. We independently hardened it with https://github.com/trailofbits/fickling/commit/b9e690c5a57ee9cd341de947fc6151959f4ae359 to reduce the risk of obtaining direct module references while evading detection. https://github.com/python/cpython/blob/6d1e9ceed3e70ebc3995
O3 Security · Impact-Aware SCA

Is GHSA-5cxw-w2xg-2m8h in your dependencies?

Find it across PyPI, including transitive dependencies.

fickling's `platform` module subprocess invocation…