trust_remote_code and the ML Orchestration CVE Class
A second family of ML supply-chain CVEs has nothing to do with model weights and everything to do with the glue: transformers' trust_remote_code, langchain expression surfaces, and template injection in orchestration libraries.
The deserialization CVE class gets most of the attention because “loading a model runs code” is a memorable headline. But a second family of ML supply-chain CVEs has nothing to do with model weights and everything to do with the glue between them: the orchestration libraries that load custom model code, evaluate expressions, and render prompt templates. These are CWE-94 (code injection) and CWE-1336 (template injection) flaws, and they are arguably more dangerous in production because they execute on attacker-influenced input at runtime, not just on a one-time model load.
transformers and trust_remote_code
Hugging Face transformers supports models whose architecture is defined by Python files shipped in the model repository. Loading such a model with trust_remote_code=True imports and runs that code in your process. The flag exists because some legitimate architectures need it, and the documentation is explicit that you should only enable it for repositories you trust and ideally pin to a specific revision.
In practice the flag is copied from tutorials and left on. The moment it is set against a repository you do not control, “download this model” becomes “execute this repository’s code.” There is frequently no separate CVE for this — it is documented intended behavior — which is exactly why it is dangerous as a tracking problem: a defender scanning a CVE feed will not see “you enabled trust_remote_code on an untrusted repo,” yet it is functionally equivalent to the deserialization RCEs that do get CVEs. Treat it as a standing exposure to audit in your own code, not something the feed will surface for you.
langchain and the expression/eval surface
Where there is a CVE, the langchain ecosystem is the canonical case study. CVE-2023-29374 ↗ covered code execution in LLMMathChain: the chain took LLM output and evaluated it as a Python expression, so prompt-influenced text reached an eval-like sink. CVE-2024-21513 ↗ covered code execution in langchain-experimental through a similar path. These are CWE-94: untrusted text — and LLM output driven by user input is untrusted text — flowing into a code-generation or evaluation primitive.
The structural lesson generalizes past langchain. Any orchestration component that (a) takes model output and (b) feeds it to eval, exec, a math parser, a code interpreter tool, or a shell, is one prompt-injection away from RCE. The CVE history of these libraries is not a story about one buggy function; it is a series of independent rediscoveries that “LLM output is an untrusted input channel” applied to whatever sink was nearest.
Template injection: the quieter variant
Prompt templates are rendered by template engines. If user-controlled data is interpolated into a template that is itself rendered — rather than passed as a bound variable — you have CWE-1336 server-side template injection, and depending on the engine that ranges from data disclosure to code execution. This appears in ML stacks wherever prompt construction concatenates user input into a Jinja-style template instead of parameterizing it. It rarely produces a dramatic ML CVE, which is precisely why it survives in codebases: it looks like string formatting, not a sink.
Reading these CVEs correctly
For this class the triage question is different from deserialization. It is not “did I produce these bytes” but: does untrusted runtime input — user prompts, retrieved documents, tool output — reach a code, expression, or template sink? A langchain code-execution CVE is critical for an app that pipes user chat into an agent with a Python tool, and close to irrelevant for an app that uses the library only for static, server-authored chains with no eval-capable tools. Same CVE, opposite exposure, and the CVSS vector — typically scored for the worst case — will not distinguish them. Your data-flow does.
What actually mitigates it
- Default
trust_remote_codeto off and pin revisions. If a model genuinely requires it, vendor and review the model code, then load it pinned to a reviewed commit — never a moving branch. - Keep model output away from code sinks. Do not
evalLLM output. Replace math/code chains with sandboxed, allow-listed evaluators, or remove the capability if the use case does not need it. - Parameterize prompts; never render user input as a template. Pass user data as bound variables to a template that is authored entirely by you.
- Treat orchestration libraries as a tracked CVE surface in their own right. langchain, langchain-experimental, transformers, llama-index and similar move fast and have a recurring code-execution history. Pin versions, watch their advisories specifically, and re-evaluate exposure when your agent’s tool list changes — not only when a CVE drops.
Weight-loading CVEs and orchestration CVEs are two halves of the same supply chain. The first asks whether you trust the bytes; the second asks whether you trust the inputs flowing through the glue at runtime. A tracker that only watches the first half is reporting on half the attack surface.
Sources
- transformers: trust_remote_code documentation and warning
- CVE-2023-29374: LangChain LLMMathChain code execution — NVD
- CVE-2024-21513: langchain-experimental code execution — NVD
- CWE-94: Improper Control of Generation of Code (Code Injection) — MITRE
- CWE-1336: Improper Neutralization of Special Elements Used in a Template Engine — MITRE
ML CVEs — in your inbox
CVEs in ML libraries, frameworks, and the AI/ML supply chain. — delivered when there's something worth your inbox.
No spam. Unsubscribe anytime.
Related
Hugging Face Transformers & Hub: Supply-Chain Risks and Real Advisories
The Hugging Face ecosystem is the npm of machine learning — and it carries the same supply-chain exposure. A tour of verified Transformers CVEs and what they reveal about trusting models, configs, and the tooling meant to protect you.
PyTorch Security: Notable CVEs and How to Harden Your Loading Path
PyTorch's most consequential CVEs cluster around one thing — loading a model file that runs code. A walk through the verified entries, what each actually requires to exploit, and the hardening that holds.
Unsafe Model Deserialization: The Pickle Problem Behind ML CVEs
Loading a model file can execute arbitrary code. This is the single most repeated vulnerability class in the ML supply chain — the real CVEs, why the fixes keep arriving late, and what actually mitigates it.