The Trust Boundary Is Not the Model: How Agent Frameworks Turn Prompt Injection into RCE
A prompt injection that reaches eval() is not a model failure. It is an architecture failure — and it keeps happening in the same way across the agent frameworks operators actually deploy.
In the last eight months, four widely used agent frameworks have shipped Critical-severity RCE vulnerabilities that share a single root cause: the trust boundary was assumed to exist at the model layer, but the execution primitive lives in the framework code around it. When the model is wired to tools, prompt injection stops being a content problem and becomes a code-execution primitive. The vulnerabilities in Microsoft Semantic Kernel, vLLM, PraisonAI, and Langflow each demonstrate a different facet of the same architectural blind spot.
The pattern: execution sinks the model can reach
Semantic Kernel: the vector-store filter that became an eval() sink
Microsoft’s May 2026 disclosure details two CVEs in Semantic Kernel. CVE-2026-26030 sits in the Python SDK’s InMemoryVectorStore filter functionality. The Search Plugin exposes a filter parameter that the model controls directly. That parameter flows into a lambda expression that gets formatted and executed inside eval() — no sanitization, no allowlist, just string interpolation into executable Python.
The exploit chain: prompt injection → model calls Search Plugin with crafted filter → filter string escapes the template → Python AST traversal reaches BuiltinImporter → os.system() executes arbitrary commands. The fix in python-1.39.4 required four layers of protection to close every escape primitive.
CVE-2026-25592 in the .NET SDK is a sandbox escape via SessionsPythonPlugin. The DownloadFileAsync helper — which runs on the host, not in the Azure Container Apps sandbox — was accidentally marked [KernelFunction], advertising it to the model as a callable tool. The model controls localFilePath. Result: arbitrary file write on the host filesystem, demonstrated by writing to the Windows Startup folder for persistence. Fixed in Microsoft.SemanticKernel.Plugins.Core 1.71.0 by removing the attribute and adding path validation.
Both CVEs share the mechanism: a framework function that crosses a trust boundary (sandbox→host, data→code) was exposed to the model without the boundary checks the architecture assumed existed.
vLLM: trust_remote_code=false was ignored at model load
CVE-2026-22807 affects vLLM 0.10.1 through 0.13.x. During model resolution, vLLM iterates auto_map entries from the model’s config.json and calls try_get_class_from_dynamic_module, which delegates to Transformers’ get_class_from_dynamic_module — and executes the module code. This happens before any request handling, at server startup, and ignores trust_remote_code=false.
An attacker who can influence the model repository or local path (a malicious Hugging Face repo, a compromised internal model store, a supply-chain injection) achieves arbitrary code execution on the vLLM host during initialization. No API request needed. The fix in vLLM 0.14.0 propagates trust_remote_code through the call chain to the dynamic module loader.
This is not a model vulnerability. It is a configuration-gating failure: the flag that operators trust to gate remote code execution was not wired to the code path that actually executes remote code.
PraisonAI: the official A2A example that ships an unauthenticated eval() endpoint
CVE-2026-47391 in PraisonAI < 4.6.40 is a Critical chain in the first-party A2A server example:
- The example exposes an A2A JSON-RPC endpoint without configuring
auth_token - It binds to
0.0.0.0(public interface) - It registers a
calculate(expression)tool implemented aseval(expression)
An unauthenticated remote client sends message/send to /a2a; the request reaches agent.chat(); a real Gemini LLM (gemini/gemini-2.5-flash-lite) invokes the calculate tool; the eval() executes arbitrary Python in the server process. Confirmed with a real LLM canary that wrote a marker file from an unauthenticated HTTP request.
The advisory is explicit: this affects deployments following the official example. The fix requires removing eval() from examples, defaulting A2A.serve() to 127.0.0.1, requiring authentication for public binding, and treating code-execution tools as dangerous regardless of function name.
Langflow: “validation” that executes LLM-generated code
CVE-2026-33873 in Langflow < 1.9.0: the Agentic Assistant feature executes LLM-generated Python code during its validation phase. The chain: /assist → execute_flow_with_validation() → execute_flow_file() → LLM returns component code → extract_component_code() → validate_component_code() → create_class() → exec(...) instantiates the generated class server-side.
The validation path was supposed to be static analysis. Instead, it crosses a trust boundary and becomes an execution sink. The initial fix added an AST-based scanner blocking dangerous imports (socket, urllib.request, http.client, os.dup2) — but this is defense-in-depth, not a sandbox. The underlying exec remains in the validation path (tracked in issue #12787).
What connects them: the trust boundary is in the wrong place
| Framework | CVE | Execution Sink | Trust Boundary Assumed | Where It Actually Was |
|---|---|---|---|---|
| Semantic Kernel (Python) | CVE-2026-26030 | eval() in vector-store filter | Model output sanitization | Framework filter formatting |
| Semantic Kernel (.NET) | CVE-2026-25592 | DownloadFileAsync host file write | Sandbox isolation | [KernelFunction] attribute exposure |
| vLLM | CVE-2026-22807 | auto_map dynamic module exec() | trust_remote_code flag | Model resolution call chain |
| PraisonAI | CVE-2026-47391 | eval() in calculate tool | A2A authentication | Example binds 0.0.0.0 + no auth + eval() tool |
| Langflow | CVE-2026-33873 | exec() in validation path | Static validation | create_class() instantiation |
In every case, the component that executes code was reachable from model-controlled input, and the guard the operator expected to be there was either missing, miswired, or applied to the wrong layer.
The operator consequence
If you run agents in production, the model is not your security boundary. The model is the attack surface that reaches the boundary. The boundary is:
- Egress allowlists — deny-by-default network egress kills both payload delivery and exfiltration (as Tenet’s agent-jackstop demonstrates)
- Explicit approval gates — no auto-run on tool calls that cross trust boundaries (file writes, network calls, code execution)
- Credential isolation at the subprocess level — sandbox filesystem deny-lists (
sandbox.filesystem.denyRead), not prompt-levelReadtool blocks - Provenance separation — untrusted content (web fetches, tool outputs, external data) must not share context with privileged credentials and outbound tools
- Static validation that is actually static — no
exec(),eval(), dynamic imports, or class instantiation in validation paths
The uncomfortable truth from Microsoft’s research: “Your LLM is not a security boundary. The tools you expose define your attacker’s affected scope. Any tool parameter the model can influence must be treated as attacker-controlled input.”
Sandboxes, trust_remote_code flags, and content filters are not the boundary. They are layers that reduce the attack surface. The boundary is the runtime enforcement of what the model is allowed to cause — and that enforcement must live in the framework, not in the prompt.
Sources
- Microsoft Security Blog: When prompts become shells — RCE vulnerabilities in AI agent frameworks (May 7, 2026)
- GitHub Advisory: CVE-2026-26030 — Semantic Kernel InMemoryVectorStore RCE
- GitHub Advisory: CVE-2026-25592 — Semantic Kernel .NET SessionsPythonPlugin Arbitrary File Write
- GitHub Advisory: CVE-2026-22807 — vLLM RCE via auto_map dynamic module loading
- NVD: CVE-2026-22807 Detail
- GitHub Advisory: CVE-2026-47391 — PraisonAI Unauthenticated A2A eval() RCE
- NVD: CVE-2026-47391 Detail
- GitHub Advisory: CVE-2026-33873 — Langflow Agentic Assistant Validation Code Execution
- NVD: CVE-2026-33873 Detail
- Langflow PR #13784: Fix for CVE-2026-33873 scanner blocklist gap
- Tenet Security: Agentjacking — One Fake Bug Report Hijacked a $250B Company’s AI Agent
- tenet-security/agent-jackstop: Hardening configs for Cursor and Claude Code