CVE-2026-16760 (GCVE-0-2026-16760)
Vulnerability from cvelistv5 – Published: 2026-10-30 21:16 – Updated: 2026-10-30 21:16
VLAI
EPSS
VEX
Title
Fickling check_safety() bypass: likely_safe_imports grants module-origin trust to unvalidated standard library callables
Summary
In Trail of Bits fickling through 0.1.12, the _process_import() method in fickle.py adds an imported name to the likely_safe_imports set whenever the source module is present in sys.stdlib_module_names and the name is absent from the UNSAFE_IMPORTS denylist, without inspecting what the name resolves to or how it behaves. The OvertlyBadEvals analysis pass in analysis.py then unconditionally skips any call whose function name appears in likely_safe_imports, including calls that would otherwise be flagged as overtly dangerous. As a result, any callable reachable through a non-blocked standard library module inherits module-level trust regardless of its own behavior, and check_safety() returns LIKELY_SAFE with zero findings for pickle payloads that reach code execution or file write through such callables. Demonstrated primitives: dataclasses._create_fn, which passes an attacker-controlled function body to exec() and yields arbitrary code execution on Python 3.7 through 3.12 (the internal _create_fn function was removed in Python 3.13); mailcap.findmatch, which internally calls os.system() on a test command taken from an attacker-controlled caps dictionary, yielding arbitrary code execution on Python versions through 3.12 (the mailcap module was removed in Python 3.13); and readline.add_history() followed by readline.write_history_file(), which writes attacker-controlled content to an arbitrary filesystem path (POSIX platforms, where the readline module is available). fickling.load() chains check_safety() into pickle.loads() as an explicit security gate, so a LIKELY_SAFE verdict causes the payload to be deserialized and executed with the privileges of the victim process. The root cause is the inference of callable safety from module origin; it is independent of, and separately fixable from, the dotted __qualname__ resolution weakness tracked as CVE-2026-118938, which this advisory does not address. As of 2026-10-30 the three demonstrated modules were added to UNSAFE_IMPORTS on the vendor master branch (commit d011709) pending release; released versions through 0.1.12 remain affected, and the module-origin trust root cause persists, as demonstrated by the related CVE-2026-118938 remaining exploitable on that same build.
Severity
8.8 (High)
Assigner
References
Impacted products
1 product
| Vendor | Product | Version | CPE status | |
|---|---|---|---|---|
| trailofbits | fickling |
Affected:
0 , ≤ 0.1.12
(custom)
|
guessed |
{
"containers": {
"cna": {
"affected": [
{
"collectionURL": "https://pypi.org/project/fickling/",
"defaultStatus": "unaffected",
"packageName": "fickling",
"product": "fickling",
"vendor": "trailofbits",
"versions": [
{
"lessThanOrEqual": "0.1.12",
"status": "affected",
"version": "0",
"versionType": "custom"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Christopher Aziz (Bombadil Systems LLC)"
}
],
"descriptions": [
{
"lang": "en",
"supportingMedia": [
{
"base64": false,
"type": "text/html",
"value": "\u003cp\u003eIn Trail of Bits fickling through 0.1.12, the _process_import() method in fickle.py adds an imported name to the likely_safe_imports set whenever the source module is present in sys.stdlib_module_names and the name is absent from the UNSAFE_IMPORTS denylist, without inspecting what the name resolves to or how it behaves. The OvertlyBadEvals analysis pass in analysis.py then unconditionally skips any call whose function name appears in likely_safe_imports, including calls that would otherwise be flagged as overtly dangerous. As a result, any callable reachable through a non-blocked standard library module inherits module-level trust regardless of its own behavior, and check_safety() returns LIKELY_SAFE with zero findings for pickle payloads that reach code execution or file write through such callables. Demonstrated primitives: dataclasses._create_fn, which passes an attacker-controlled function body to exec() and yields arbitrary code execution on Python 3.7 through 3.12 (the internal _create_fn function was removed in Python 3.13); mailcap.findmatch, which internally calls os.system() on a test command taken from an attacker-controlled caps dictionary, yielding arbitrary code execution on Python versions through 3.12 (the mailcap module was removed in Python 3.13); and readline.add_history() followed by readline.write_history_file(), which writes attacker-controlled content to an arbitrary filesystem path (POSIX platforms, where the readline module is available). fickling.load() chains check_safety() into pickle.loads() as an explicit security gate, so a LIKELY_SAFE verdict causes the payload to be deserialized and executed with the privileges of the victim process. The root cause is the inference of callable safety from module origin; it is independent of, and separately fixable from, the dotted __qualname__ resolution weakness tracked as CVE-2026-118938, which this advisory does not address. As of 2026-10-30 the three demonstrated modules were added to UNSAFE_IMPORTS on the vendor master branch (commit d011709) pending release; released versions through 0.1.12 remain affected, and the module-origin trust root cause persists, as demonstrated by the related CVE-2026-118938 remaining exploitable on that same build.\u003c/p\u003e"
}
],
"value": "In Trail of Bits fickling through 0.1.12, the _process_import() method in fickle.py adds an imported name to the likely_safe_imports set whenever the source module is present in sys.stdlib_module_names and the name is absent from the UNSAFE_IMPORTS denylist, without inspecting what the name resolves to or how it behaves. The OvertlyBadEvals analysis pass in analysis.py then unconditionally skips any call whose function name appears in likely_safe_imports, including calls that would otherwise be flagged as overtly dangerous. As a result, any callable reachable through a non-blocked standard library module inherits module-level trust regardless of its own behavior, and check_safety() returns LIKELY_SAFE with zero findings for pickle payloads that reach code execution or file write through such callables. Demonstrated primitives: dataclasses._create_fn, which passes an attacker-controlled function body to exec() and yields arbitrary code execution on Python 3.7 through 3.12 (the internal _create_fn function was removed in Python 3.13); mailcap.findmatch, which internally calls os.system() on a test command taken from an attacker-controlled caps dictionary, yielding arbitrary code execution on Python versions through 3.12 (the mailcap module was removed in Python 3.13); and readline.add_history() followed by readline.write_history_file(), which writes attacker-controlled content to an arbitrary filesystem path (POSIX platforms, where the readline module is available). fickling.load() chains check_safety() into pickle.loads() as an explicit security gate, so a LIKELY_SAFE verdict causes the payload to be deserialized and executed with the privileges of the victim process. The root cause is the inference of callable safety from module origin; it is independent of, and separately fixable from, the dotted __qualname__ resolution weakness tracked as CVE-2026-118938, which this advisory does not address. As of 2026-10-30 the three demonstrated modules were added to UNSAFE_IMPORTS on the vendor master branch (commit d011709) pending release; released versions through 0.1.12 remain affected, and the module-origin trust root cause persists, as demonstrated by the related CVE-2026-118938 remaining exploitable on that same build."
}
],
"impacts": [
{
"descriptions": [
{
"lang": "en",
"value": "An attacker can craft a malicious pickle that invokes a dangerous callable imported from a standard library module not present in UNSAFE_IMPORTS. The name is added to likely_safe_imports by _process_import(), causing OvertlyBadEvals to skip the call, so check_safety() returns LIKELY_SAFE and fickling.load() proceeds to deserialize the payload. This yields arbitrary code execution via dataclasses._create_fn or mailcap.findmatch on Python versions through 3.12, and arbitrary file write with attacker-controlled content via readline.write_history_file on POSIX platforms across supported Python versions. Because the flaw is in the module-origin trust model rather than in any specific module list, adding the demonstrated modules to UNSAFE_IMPORTS does not address the root cause; additional dangerous callables remain reachable through other non-blocked standard library modules."
}
]
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "HIGH",
"baseScore": 8.8,
"baseSeverity": "HIGH",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "NONE",
"scope": "UNCHANGED",
"userInteraction": "REQUIRED",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "GENERAL"
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-693",
"description": "CWE-693 Protection Mechanism Failure",
"lang": "en",
"type": "CWE"
}
]
},
{
"descriptions": [
{
"cweId": "CWE-502",
"description": "CWE-502 Deserialization of Untrusted Data",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-10-30T21:16:31.353Z",
"orgId": "aa17e1a1-c329-4d6e-a1ed-8d0188aea082",
"shortName": "BombadilSystems"
},
"references": [
{
"name": "Bombadil Systems advisory listing",
"url": "https://bombadil.systems/advisories.html"
},
{
"name": "fickling 0.1.12 on PyPI",
"url": "https://pypi.org/project/fickling/0.1.12/"
},
{
"name": "fickling source repository",
"url": "https://github.com/trailofbits/fickling"
},
{
"name": "Vendor remediation merge commit d011709 (adds readline, dataclasses, and mailcap to UNSAFE_IMPORTS on master; the module-origin trust root cause remains)",
"url": "https://github.com/trailofbits/fickling/commit/d011709"
}
],
"source": {
"discovery": "UNKNOWN"
},
"title": "Fickling check_safety() bypass: likely_safe_imports grants module-origin trust to unvalidated standard library callables",
"x_generator": {
"engine": "Vulnogram 1.0.5"
}
}
},
"cveMetadata": {
"assignerOrgId": "aa17e1a1-c329-4d6e-a1ed-8d0188aea082",
"assignerShortName": "BombadilSystems",
"cveId": "CVE-2026-16760",
"datePublished": "2026-10-30T21:16:31.353Z",
"dateReserved": "2026-07-23T14:00:36.878Z",
"dateUpdated": "2026-10-30T21:16:31.353Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2",
"vulnerability-lookup:meta": {
"epss": {
"cve": "CVE-2026-16760",
"date": "2026-10-31",
"epss": "0.00455",
"percentile": "0.39487"
},
"nvd": {
"cve": {
"affected": [
{
"affectedData": [
{
"collectionURL": "https://pypi.org/project/fickling/",
"defaultStatus": "unaffected",
"packageName": "fickling",
"product": "fickling",
"vendor": "trailofbits",
"versions": [
{
"lessThanOrEqual": "0.1.12",
"status": "affected",
"version": "0",
"versionType": "custom"
}
]
}
],
"source": "aa17e1a1-c329-4d6e-a1ed-8d0188aea082"
}
],
"cveTags": [],
"descriptions": [
{
"lang": "en",
"value": "In Trail of Bits fickling through 0.1.12, the _process_import() method in fickle.py adds an imported name to the likely_safe_imports set whenever the source module is present in sys.stdlib_module_names and the name is absent from the UNSAFE_IMPORTS denylist, without inspecting what the name resolves to or how it behaves. The OvertlyBadEvals analysis pass in analysis.py then unconditionally skips any call whose function name appears in likely_safe_imports, including calls that would otherwise be flagged as overtly dangerous. As a result, any callable reachable through a non-blocked standard library module inherits module-level trust regardless of its own behavior, and check_safety() returns LIKELY_SAFE with zero findings for pickle payloads that reach code execution or file write through such callables. Demonstrated primitives: dataclasses._create_fn, which passes an attacker-controlled function body to exec() and yields arbitrary code execution on Python 3.7 through 3.12 (the internal _create_fn function was removed in Python 3.13); mailcap.findmatch, which internally calls os.system() on a test command taken from an attacker-controlled caps dictionary, yielding arbitrary code execution on Python versions through 3.12 (the mailcap module was removed in Python 3.13); and readline.add_history() followed by readline.write_history_file(), which writes attacker-controlled content to an arbitrary filesystem path (POSIX platforms, where the readline module is available). fickling.load() chains check_safety() into pickle.loads() as an explicit security gate, so a LIKELY_SAFE verdict causes the payload to be deserialized and executed with the privileges of the victim process. The root cause is the inference of callable safety from module origin; it is independent of, and separately fixable from, the dotted __qualname__ resolution weakness tracked as CVE-2026-118938, which this advisory does not address. As of 2026-10-30 the three demonstrated modules were added to UNSAFE_IMPORTS on the vendor master branch (commit d011709) pending release; released versions through 0.1.12 remain affected, and the module-origin trust root cause persists, as demonstrated by the related CVE-2026-118938 remaining exploitable on that same build."
}
],
"id": "CVE-2026-16760",
"lastModified": "2026-10-30T22:16:54.193",
"metrics": {
"cvssMetricV31": [
{
"cvssData": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "HIGH",
"baseScore": 8.8,
"baseSeverity": "HIGH",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "NONE",
"scope": "UNCHANGED",
"userInteraction": "REQUIRED",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
"version": "3.1"
},
"exploitabilityScore": 2.8,
"impactScore": 5.9,
"source": "aa17e1a1-c329-4d6e-a1ed-8d0188aea082",
"type": "Secondary"
}
]
},
"published": "2026-10-30T22:16:54.193",
"references": [
{
"source": "aa17e1a1-c329-4d6e-a1ed-8d0188aea082",
"url": "https://bombadil.systems/advisories.html"
},
{
"source": "aa17e1a1-c329-4d6e-a1ed-8d0188aea082",
"url": "https://github.com/trailofbits/fickling"
},
{
"source": "aa17e1a1-c329-4d6e-a1ed-8d0188aea082",
"url": "https://github.com/trailofbits/fickling/commit/d011709"
},
{
"source": "aa17e1a1-c329-4d6e-a1ed-8d0188aea082",
"url": "https://pypi.org/project/fickling/0.1.12/"
}
],
"sourceIdentifier": "aa17e1a1-c329-4d6e-a1ed-8d0188aea082",
"vulnStatus": "Received",
"weaknesses": [
{
"description": [
{
"lang": "en",
"value": "CWE-502"
},
{
"lang": "en",
"value": "CWE-693"
}
],
"source": "aa17e1a1-c329-4d6e-a1ed-8d0188aea082",
"type": "Secondary"
}
]
}
},
"redhat_vex": {
"aggregate_severity": "Important",
"current_release_date": "2026-10-30T22:10:53+00:00",
"cve": "CVE-2026-16760",
"id": "CVE-2026-16760",
"initial_release_date": "2026-10-30T21:16:31.353000+00:00",
"product_status:known_affected": "2",
"source": "Red Hat CSAF VEX",
"status": "final",
"title": "fickling: fickling: Arbitrary code execution via safety check bypass",
"url": "https://security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-16760.json",
"version": "3"
}
}
}
Loading…
Loading…
Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.
Experimental. This forecast is provided for visualization only and may change without notice. Do not use it for operational decisions.
Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline
Sightings and recorded dates, grouped by day · UTC
Loading timeline…
Loading…
Loading…
The MITRE ATT&CK techniques below are AI-generated suggestions, inferred from the description of the
vulnerability by the CIRCL/vulnerability-attack-technique-classification-roberta-base
model, served locally by ML-Gateway.
They have not been verified by an analyst and are provided for guidance only.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Loading…
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.