Skip to main content
Vulnerability Database/CVE-2026-94091

CVE-2026-94091: Gensim Model Loader RCE Vulnerability

CVE-2026-94091 is a deserialization flaw in piskvorky gensim Model Loader allowing remote code execution through unsafe pickle operations. This article covers the technical details, affected versions, and security measures.

Published:

CVE-2026-94091 Overview

CVE-2026-94091 is an insecure deserialization vulnerability in the piskvorky gensim library, affecting versions up to 4.4.0. The flaw resides in the Load function of gensim/utils.py, part of the Model Loader component. An attacker who controls the fname argument can trigger unsafe deserialization through Python's pickle.load invocation inside SaveLoad.load. The issue is tracked under [CWE-20] (Improper Input Validation) and is exploitable remotely when applications load attacker-supplied model files. A public exploit reference exists, and the maintainer closed the upstream report (GitHub Issue #3663) without a fix, leaving the unsafe code path present at the development HEAD.

Critical Impact

Loading a malicious gensim model file can result in arbitrary Python code execution in the process that calls the model loader.

Affected Products

  • piskvorky gensim versions up to and including 4.4.0
  • The gensim/utils.py Model Loader component (SaveLoad.load)
  • Applications and ML pipelines that call gensim loaders on untrusted file paths or URLs

Discovery Timeline

  • 2026-09-20 - CVE-2026-94091 published to NVD
  • 2026-09-21 - Last updated in NVD database

Technical Details for CVE-2026-94091

Vulnerability Analysis

The vulnerability is a classic Python pickle deserialization flaw. The gensim SaveLoad.load class method, invoked through the Load function in gensim/utils.py, calls pickle.load on the file identified by the fname argument. Python's pickle format supports object reconstruction via the __reduce__ protocol, which allows arbitrary callables to execute during deserialization. When an application passes an attacker-controlled path, URL, or file into gensim's model loader, the deserializer executes embedded payloads in the process context. The upstream report (GitHub Issue #3663) was closed same-day without a patch, and the repository's last push predates the disclosure, so the unsafe call remains at develop HEAD.

Root Cause

The root cause is trust placed in serialized model files. pickle.load performs no validation of the data stream and reconstructs any object graph the input describes. Because gensim's SaveLoad interface is a primary user-facing API for persisting and restoring models, downstream projects routinely wire it to file paths that may originate from user uploads, model registries, or remote storage. There is no allowlist, signature check, or safer serializer alternative enforced in the affected code path.

Attack Vector

An attacker crafts a malicious pickle file that mimics a gensim model artifact. The attacker then delivers this file to a target that calls gensim.utils.SaveLoad.load(fname) — for example, a web service that accepts uploaded embeddings, a training pipeline that pulls models from a shared bucket, or a notebook that fetches a model from an untrusted URL. When the loader deserializes the file, the embedded __reduce__ callable runs, executing attacker-chosen Python code with the privileges of the loading process. Exploitation requires that the victim application load the attacker-supplied file, which typically involves some user interaction or an insecurely configured retrieval workflow.

No verified exploit code is reproduced here. Refer to the VulDB entry for CVE-2026-94091 for the public exploit reference and technical notes.

Detection Methods for CVE-2026-94091

Indicators of Compromise

  • Unexpected child processes (for example, sh, bash, python, curl, wget) spawned by Python interpreters running gensim workloads.
  • Outbound network connections initiated by ML worker processes immediately after a model load operation.
  • Newly written files or scheduled tasks created by user accounts that run data-science services after ingesting a third-party model.
  • Pickle files present in model directories that contain opcodes such as c__builtin__\nexec or references to os.system, subprocess, or posix.system.

Detection Strategies

  • Instrument Python applications to log every call site of gensim.utils.SaveLoad.load along with the resolved fname and its source.
  • Statically scan candidate model files for dangerous pickle opcodes (GLOBAL, REDUCE, BUILD) referencing execution primitives before loading.
  • Deploy endpoint behavioral analytics to flag Python processes that transition from file I/O to process creation or network egress within a short window.

Monitoring Recommendations

  • Alert on gensim workloads reading model artifacts from writable network shares, public buckets, or user upload directories.
  • Monitor package inventories for gensim versions at or below 4.4.0 across build hosts, notebooks, and container images.
  • Forward Python audit hook events (sys.addaudithook) covering pickle.find_class to a central log store for correlation.

How to Mitigate CVE-2026-94091

Immediate Actions Required

  • Treat all .pkl, .model, and gensim-serialized files from external sources as untrusted and quarantine them until validated.
  • Restrict who can write to directories referenced by gensim load calls, and require signed provenance metadata for model artifacts.
  • Run gensim workloads under least-privilege service accounts inside sandboxed containers with restricted network egress.
  • Inventory applications that call gensim.utils.SaveLoad.load or Word2Vec.load, KeyedVectors.load, and similar wrappers to prioritize remediation.

Patch Information

No upstream fix is available as of the disclosure. The maintainer closed GitHub Issue #3663 without a patch, and the repository's last push predates the CVE. Track the gensim GitHub repository for future security releases and pin dependency versions once a fix is published.

Workarounds

  • Replace pickle-based persistence with safer formats such as numpy.save/numpy.load for vector arrays, or export vectors to text/JSON where feasible.
  • Wrap gensim loading in a subprocess that runs with no-new-privileges, a read-only filesystem, and no outbound network access, then serialize only the resulting vectors back to the parent.
  • Implement a pickle allowlist by subclassing pickle.Unpickler and overriding find_class to reject any class outside a vetted set of gensim and numpy types before delegating to SaveLoad.load.
  • Verify SHA-256 hashes and cryptographic signatures on model files against a trusted manifest prior to invoking the loader.
bash
# Configuration example: quarantine gensim model loads and pin the vulnerable version for tracking
pip list --format=freeze | grep -i '^gensim=='

# Deny write access to the model directory for the service account
chown -R root:mlsvc /opt/models
chmod -R 750 /opt/models
find /opt/models -type f -name '*.pkl' -exec sha256sum {} \; > /opt/models/manifest.sha256

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.