A Prompt Injection Turned Into a Shell: Inside Semantic Kernel's Two RCE CVEs Microsoft disclosed two remote code execution vulnerabilities in its open-source Semantic Kernel agent framework, CVE-2026-26030 and CVE-2026-25592, both stemming from model-controlled input reaching powerful primitives without sanitization. The Python SDK's InMemoryVectorStore built metadata filters as lambda expressions evaluated with eval(), bypassed via Python class-hierarchy traversal, while the .NET SDK's SessionsPythonPlugin DownloadFileAsync wrote files to arbitrary paths, including the Windows Startup folder for persistence. Fixes shipped in semantic-kernel 1.39.4 for Python and .NET SDK 1.71.0. Two ordinary agent-framework conveniences, a filterable vector search and a file-download tool, turned into remote code execution once an LLM's output was trusted a little too much. Here's what happened in Microsoft Semantic Kernel, and what to check in your own agent code today. Prompt injection usually gets discussed as an output-quality problem: the model says something it shouldn't, or does something a user didn't ask for. CVE-2026-26030 and CVE-2026-25592, two vulnerabilities Microsoft disclosed in its Semantic Kernel framework, are a sharper reminder of what it can become: full remote code execution, demonstrated in Microsoft's own writeup by launching calc.exe on the machine running the agent. Semantic Kernel is Microsoft's open-source framework for building agents and wiring LLMs into tool-calling applications, widely used both inside Microsoft's own ecosystem and in third-party projects. Both vulnerabilities follow the same underlying pattern in different SDKs, and that pattern is the actually useful thing to take away from this. This one lives in the Python SDK's InMemoryVectorStore . When an agent searches a vector store with a metadata filter, Semantic Kernel builds that filter as a Python lambda expression and evaluates it with eval at query time. The filter parameters can include AI-model-controlled input, and according to Microsoft's account, that input was not sanitized before being interpolated into the expression. The framework did have a blocklist meant to catch dangerous constructs. It was bypassed using Python's class hierarchy traversal, essentially reaching dangerous built-ins through an indirect attribute-access path the blocklist didn't anticipate rather than referencing them directly. Microsoft's proof of concept, built around a "hotel finder" agent scenario, used this path to launch calc.exe . The fix shipped in semantic-kernel 1.39.4 for Python. The second vulnerability is in the .NET SDK's SessionsPythonPlugin . Its DownloadFileAsync function was exposed to the model through a KernelFunction attribute, the standard way Semantic Kernel marks a method as callable by the agent, without validating the destination path. That let a sufficiently crafted prompt cause the agent to write a file to an arbitrary location on the host, including the Windows Startup folder. A file dropped in Startup runs automatically the next time the user logs in. That's the more consequential part of this one: it doesn't just execute code inside the agent's process, it persists past the session and past whatever sandbox the agent's normal execution was running in, because a container's sandbox isolation typically doesn't extend to filesystem locations mounted or shared with the host, and Startup-folder execution triggers outside the container entirely on the next host login. The fix shipped in the .NET SDK 1.71.0, the same day as the Python fix. Strip away the specifics and both vulnerabilities are the same mistake: a powerful, code-adjacent primitive, eval in one case, unrestricted file I/O in the other, received a value that ultimately traced back to model output, and nobody treated that value as attacker-controlled. That's the actual lesson, and it generalizes far past these two specific CVEs. An LLM's output is attacker-controlled the moment it has processed any untrusted content: a scraped webpage, a user-supplied document, retrieved search results, another agent's message. If that output can influence a filter string that gets evaluated as code, or a path that gets written to without validation, or really any string that reaches a powerful primitive without going through a narrow, explicit contract, you have the shape of this bug, regardless of which framework you're using. KernelFunction in Semantic Kernel, the equivalent decorator or registration call in whatever you're using . For each one, ask: if the model called this with the worst possible string, what happens? eval exec Agent frameworks compete partly on how much they let a model do without hand-written glue code, which means each new release tends to add more direct, convenient bridges between "thing the model said" and "thing that actually executes." Every one of those bridges is a candidate for this exact failure mode. Semantic Kernel isn't unusually careless here; it's unusually well-documented, because Microsoft wrote the postmortem itself. The realistic assumption for anyone building on any agent framework is that equivalent, undisclosed instances of this pattern exist elsewhere, and the fix is the same regardless of framework: treat model output as untrusted input everywhere it lands, not just at the final response to the user. This story was written with the assistance of an AI writing program.