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.

