/

CVE-2026-68770

Severity:

CRITICAL RISK

(9.8)

Code Execution (CWE-94) via SentenceTransformers Loader

CVE-2026-68770

Deferred

Vulnerability type

Category:

Code Injection

CWE:

CWE-94

Impact:

Arbitrary Code Execution

Severity:

CRITICAL RISK

(9.8)

CVSS version:

3.1

Catch this CVE while code is being written

Detect vulnerable code directly in pull requests, so CVEs are fixed before merge.

Summary

A logic flaw in sentence-transformers allows arbitrary code execution when loading local models, even when trust_remote_code=False is specified.

If an attacker can control files in a model directory, they can plant malicious Python modules that execute during model import, bypassing the intended security guard.

Affected context

This vulnerability affects applications that use the sentence-transformers library to load models from the local filesystem, especially via SentenceTransformer(path, trust_remote_code=False).

It becomes relevant when an application relies on the trust_remote_code flag to prevent untrusted code execution but loads models from directories that may be writable, shared, or otherwise influenced by untrusted parties.

The issue is triggered during the model loading process when the import_module_class helper evaluates guard conditions for importing model-specific Python files.

Exploit preconditions

  • Attack surface: Local or adjacent environment where sentence-transformers loads models from disk
  • Required access: Ability to create, modify, or replace files within a target model directory (including modules.json and modeling_*.py)
  • Trigger point: An application calls SentenceTransformer(path, trust_remote_code=False), causing import_module_class in util/misc.py to import model-specific modules
  • Why exploitation is possible: The guard logic treats any existing local path as trusted due to the or os.path.exists(model_name_or_path) clause, bypassing the trust_remote_code=False control and allowing unvalidated Python modules to be imported and executed

Why this happens

The root cause is a flawed trust gate in the import_module_class helper that conflates "local existence" with "trusted code."

By including or os.path.exists(model_name_or_path) in the guard condition, the loader effectively overrides the trust_remote_code flag whenever the model path exists on disk.

This aligns with CWE-94: Improper Control of Generation of Code, because application logic allows unchecked, attacker-controlled Python files (e.g., modeling_*.py referenced from modules.json) to be imported and executed as part of normal model loading.

Conceptually, the bug is an authorization and trust boundary mistake: the system assumes that local files are inherently safe, and fails to enforce the documented security contract around trusted versus untrusted model code.

Potential impact

  • Attackers may execute arbitrary Python code within the application process during model loading.
  • Malicious code could access environment secrets, configuration files, or other sensitive data available to the process.
  • Compromise of the ML pipeline, including model tampering, data exfiltration, or sabotage of inference behavior.
  • Use of the compromised application as a foothold for lateral movement within the host or container environment.

General mitigation guidance

Effective mitigation focuses on tightening trust boundaries and avoiding implicit trust in local model directories.

Pattern-based defensive measures include:

  • Enforcing strict trust checks that do not rely solely on path existence; tie execution of model-specific code to explicit trust configuration.
  • Treating model directories as untrusted input: do not automatically import Python modules from them without validation or sandboxing.
  • Separating model data (weights, configs) from executable code, and prefer data-only formats that do not require dynamic imports during loading.
  • Running sentence-transformers in a least-privilege environment, limiting filesystem access and available secrets to reduce blast radius if code runs.
  • Applying defense-in-depth around model loading paths (e.g., restricting write permissions on model directories to trusted deployment processes only).

How teams detect issues like this

Organizations can look for this pattern using:

  • Static analysis rules that flag dynamic imports or loader logic conditioned on simple existence checks (e.g., os.path.exists) in security-sensitive helpers.
  • Code review practices that scrutinize trust_remote_code and similar flags, ensuring that documented guarantees match actual control flow.
  • Policies that disallow importing executable Python modules from unvalidated model directories, enforced by linters or custom CI checks.
  • Runtime monitoring that detects unexpected module imports from model directories or suspicious file modifications before model load.

Security scanning tools that understand Python import patterns and dynamic loading constructs can help identify similar trust gate flaws in other components.

Sources

SourceLink
github.comgithub.com/huggingface/sentence-transformers
github.comgithub.com/huggingface/sentence-transformers/commit/ae1acc3fb2aa2004577b297eb4a915ce7a03316a
github.comgithub.com/huggingface/sentence-transformers/issues/3801
github.comgithub.com/huggingface/sentence-transformers/pull/3807
vulncheck.comvulncheck.com/advisories/sentence-transformers-arbitrary-code-execution-on-local-model-load-despite-trust-remote-code-false

Frequently asked

questions

Exploitability depends on how model directories are managed. If an attacker can influence or write to those directories remotely (e.g., via file upload features, shared network storage, or compromised deployment pipelines), the issue can be exploited without local shell access. If directories are strictly local and controlled, the risk is reduced but still present if that control can be subverted.

The attacker must be able to create or modify files in the model directory used by sentence-transformers, including modules.json and any modeling_*.py files. This could stem from permissions on shared storage, misconfigured deployment pipelines, or any feature that writes user-controlled files to those directories.

The safest pattern is to ensure that execution of model-specific code is strictly tied to explicit trust decisions, not to filesystem existence. Loader logic should never import or execute code purely because it resides under a model path; instead, treat models as data and only load executable components when a clearly defined, verified trust mechanism approves them.

Future designs should:

  • Define clear trust boundaries for all dynamic loading mechanisms and enforce them consistently.
  • Avoid mixing data and executable code in the same untrusted directories.
  • Use configuration flags like trust_remote_code as hard gates with no fallback conditions that silently bypass them.
  • Incorporate security-focused reviews and static analysis for loader utilities, import hooks, and plugin systems during development.
Find out what's already
exploitable in your codebase.