A model’s output is untrusted input; never route it straight into an interpreter.
The caller steers the model, and the model wrote the code.
The Smart Transform component asks a language model to write a small lambda from a user instruction, then runs that lambda to filter data. Because the caller controls the instruction, they influence what the model returns. That turns the model’s output into an untrusted channel: the text about to be executed inherits the caller’s intent, not the developer’s.
TraceMint reviewed the reviewed source snapshot at Langflow 1.7.1. The generated text passed a format-only check and then went to eval, so a prompt could drive the model to emit a lambda whose body performed arbitrary operations—a prompt-injection path to remote code execution.
From instruction to model text to eval.
The component built a prompt from the instruction, called the model, and kept the reply as working text. A regular expression pulled a lambda expression out of that free-form reply. The only gate then checked that the text began with the word lambda and contained a colon—a shape assertion, not a safety one—before the string was handed to eval.
A lambda body that constructs and calls dangerous operations satisfies that same shape while doing something entirely different. Because eval executed with full builtins, the generated expression could reach imports and process operations. The consequential fact is not the model’s cleverness but the direct path from its output to the interpreter.
- Instruction to the model
The caller shapes the request.
- Extract a lambda
A regex pulls a lambda from the reply.
- Format check, then eval
Shape is checked; the string is executed.
- Instruction to the model
The same request path.
- Screen for escape gadgets
An AST check rejects unsafe constructs.
- Evaluate with safe builtins
Dangerous names are unreachable.
Conceptual control flow reconstructed from the upstream source. It is not a captured request or a TraceMint execution trace.
Screen the generated code and curate the builtins.
The later upstream change screens the generated lambda for escape gadgets before evaluating it, and evaluates it with a curated builtins mapping so names such as import, open, eval and exec are unreachable. The upstream comment describes this as defense-in-depth rather than a guaranteed sandbox. It also adds a deployment setting to block code-interpreter components where tenants should not author executable ones.
The excerpts contrast the reviewed 1.7.1 revision with the later hardening. The public commit establishes the code change; this note does not claim a causal link between the report and that change.
response = await llm.ainvoke(prompt)response_text = response.content if hasattr(response, "content") else str(response)return lambda_text.strip().startswith("lambda") and ":" in lambda_textfn: Callable[[Any], Any] = eval(lambda_text) # noqa: S307validate_code_safety(lambda_text)return eval(lambda_text, {"__builtins__": safe_builtins()}) # noqa: S307Selected upstream lines; indentation normalized. Links include surrounding code at immutable revisions.
Execution in the Langflow process.
In the reporter-supplied local reproduction against 1.7.1, an instruction that steered the model toward an import-and-execute lambda passed the format check and reached eval, running an attacker-chosen command in the Langflow process. Practical exposure depended on who could add or run that component and on the deployment’s tenancy model. TraceMint first reported this in December 2025.
- A reachable component
- The attacker can add or run the Smart Transform component.
- A steered model reply
- The instruction drives the model toward an executable lambda.
- A tenancy-dependent blast radius
- Multi-tenant deployments widen who is affected by the execution.
Treat the model reply as an attacker-controlled string.
A regression review drives the component with instructions that request an import-and-execute lambda and confirms that a hardened build refuses to evaluate them. Read the reply as untrusted input and check that the safety screen and the curated builtins both apply before execution. The scenarios below are suggested review checks, not reported TraceMint test results.
| Scenario | Expected boundary |
|---|---|
| A benign filtering lambda | The intended transform still runs. |
| A lambda that imports a module | The safety screen rejects the generated code. |
| A lambda that reaches a dangerous builtin | The curated builtins make the name unreachable. |
| Component access in multi-tenant mode | The deployment setting can block code-interpreter components. |
Put a real boundary between the model and the interpreter.
For reviewers, any feature that turns generated text into behavior needs a genuine safety boundary—an allowlist, an AST check, a restricted execution environment—between the model and the interpreter, plus a separate decision about who may reach that feature at all. A format check is not that boundary.
This study analyzes immutable Langflow source revisions and a later public commit. TraceMint’s reporter record dates the first report to December 2025; that reporter-supplied date and the public code change do not, on their own, establish that this submission exclusively identified or caused the upstream change.
Follow the evidence.
Public upstream records and immutable code revisions, reviewed 2026-09-22.
- Upstream corrective commit
1641b28f · screen generated code and evaluate with curated builtins (#13530).
- Component at the reviewed revision
Immutable revision · 47ce5bf2 · Langflow 1.7.1 · format-only check, then eval.
- Component after the hardening
Safety screen and curated builtins before evaluation.
Brief code excerpts from langflow-ai/langflow. Upstream license: MIT License. All remediation described here is upstream work.
Separate the records
The submitted date and reproduction details come from the reporter record. Public verification is limited to immutable Langflow source and the later upstream hardening commit.
No private disclosure correspondence is presented as a public source. The reviewed revision shows the LLM-output-to-eval path and the later commit shows the hardening. TraceMint’s reporter record dates the first report to December 2025; that reporter-supplied date and the public code change do not, on their own, establish that this submission exclusively identified or caused the upstream change.