In Trail of Bits fickling versions up to and including 0.1.11, the UnsafeImportsML analysis pass unconditionally calls AnalysisContext.shortencode(node) on every import node it inspects, regardless of whether the import is flagged as unsafe. This call registers the shortened code representation in the shared AnalysisContext.reportedshortenedcode set. When the MLAllowlist analysis pass subsequently runs, it calls the same shortencode() method, receives alreadyreported=True for every import, and executes a continue statement that skips its allowlist check entirely. This renders MLAllowlist dead code for all imports — it never evaluates whether an import is in the ML allowlist or not. The MLAllowlist pass was designed to catch imports of modules outside the known-safe ML ecosystem (torch, numpy, transformers, etc.) that slip past the UnsafeImports denylist. With MLAllowlist inoperative, any standard library module not in the UNSAFEIMPORTS denylist can be invoked via pickle deserialization while fickling's checksafety() returns LIKELYSAFE. The fickling.load() API chains checksafety() into pickle.loads() as an explicit security gate, meaning a LIKELYSAFE verdict causes the payload to be deserialized and executed. The root cause is shared mutable state between independently-correct analysis passes — UnsafeImportsML works as designed in isolation, MLAllowlist works as designed in isolation, but the shared reportedshortenedcode set causes UnsafeImportsML to poison MLAllowlist's deduplication logic.
{
"osv_generated_from": "https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/14xxx/CVE-2026-14535.json",
"cna_assigner": "BombadilSystems",
"cwe_ids": [
"CWE-693"
]
}