Published
- 6 min read
By Allan D - Editor, AI Security Wire
Semantic Kernel RCE: Prompt Injection Opens a Shell
On May 7, Microsoft disclosed two critical vulnerabilities in Semantic Kernel, its open-source SDK for building AI agents. CVE-2026-25592 affects the .NET SDK and enables arbitrary file writes via an accidentally exposed download function. CVE-2026-26030 affects the Python SDK and allows code execution through an unsafe eval() call in the vector store filter logic. Together they illustrate a structural risk in agentic AI frameworks: functions that should never be model-callable become attack surface when they accidentally are, and input from LLM inference pipelines reaching eval() without sanitization is simply RCE waiting to be triggered.
Both vulnerabilities are exploitable via prompt injection, requiring no credentials and no direct network access to internal systems. Semantic Kernel is used across a wide range of enterprise AI applications, including Microsoft Copilot integrations built on top of the framework.
CVE-2026-25592: Arbitrary File Write via SessionsPythonPlugin (.NET SDK)
The root cause is a single misplaced attribute. In the SessionsPythonPlugin component of the .NET SDK, the DownloadFileAsync method was decorated with [KernelFunction], the attribute that exposes a method to the language model as a callable tool. It should not have been. The method was an internal helper, and exposing it to the model turned it into an agent capability: on request, download a file from any URL and write it to a caller-specified local path.
The localFilePath parameter was passed directly to File.WriteAllBytes(). No path canonicalization. No directory allowlist. No check that the destination was within an expected directory.
The exploit chain is straightforward. An attacker places a crafted prompt in any content the agent processes: a document in its RAG corpus, an incoming email, a web page the agent browses. The injected instruction directs the model to call ExecuteCode to generate a payload script, then call DownloadFileAsync with a localFilePath pointing to a startup directory: C:\Users\Public\Start Menu\Programs\Startup\ on Windows, ~/.config/systemd/user/ on Linux. The payload executes on next login or service restart under the agent process’s privileges.
The fix in 1.71.0 does two things: removes [KernelFunction] from DownloadFileAsync entirely, making it invisible to the model, and adds ValidateLocalPathForDownload() using Path.GetFullPath() canonicalization against a permitted-directory allowlist. Similar protections were applied to upload functions in the same component.
The CVSS vector (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H) reflects what makes this particularly severe: network exploitable, no privileges required, no user interaction, scope change, full impact across all three CIA properties.
CVE-2026-26030: eval() RCE in InMemoryVectorStore (Python SDK)
The Python SDK vulnerability lives in InMemoryVectorStore. When constructing filter expressions for vector queries, the component builds a Python lambda as a string and executes it with eval(). The filter field values came from LLM-controlled or user-controlled parameters interpolated directly via f-strings.
A basic filter looked like this:
lambda x: x.city == 'Paris'
where city was the unvalidated input. Escape the string context and the lambda body is attacker-controlled:
lambda x: x.city == '' or __import__('os').system('calc.exe') or ''
Microsoft attempted a mitigation via AST validation with a blocklist checking for identifiers including eval, exec, open, and __import__. Researchers found the bypass within days of the initial patch.
The bypass used Python’s type hierarchy. By accessing __class__.__bases__[0].__subclasses__() through bracket notation and tuple() — neither blocked — the PoC traversed the class hierarchy to locate BuiltinImporter, then called load_module to load os and invoke os.system(). None of the identifiers used in the traversal appeared on the blocklist. The expression was structurally valid as a lambda, so AST parsing succeeded. The blocklist approach was fundamentally inadequate.
The fix in Python SDK 1.39.4 replaces the blocklist with an AST allowlist: only comparison operators, boolean logic, arithmetic, and literals are permitted. Function calls are allowlisted. Dangerous attribute access (__class__, __subclasses__, and similar dunder attributes) is explicitly blocked. The lambda’s name nodes are restricted to the parameter name only. Permit-by-default became deny-by-default.
A public PoC is available on GitHub. No confirmed in-the-wild exploitation has been reported, but the gap between public PoC and active exploitation in widely-deployed enterprise software is typically short.
The Structural Problem
Both vulnerabilities share a common root: insufficient boundaries between LLM inference outputs and system-level function execution.
[KernelFunction] is intended as an intentional, audited capability declaration. In practice, developers decorating internal helpers with it create tool surface that was never security-reviewed as such. Every method marked [KernelFunction] in a Semantic Kernel application should be treated as an attack surface and audited accordingly.
The eval() issue is older. Using eval() with any input that flows through an LLM, or that originates from user input processed by an LLM, cannot be made safe by a blocklist. The call in InMemoryVectorStore violated a principle that predates AI security as a discipline: do not execute strings as code when those strings derive from untrusted sources. That the strings were LLM-generated rather than directly user-supplied did not make them trusted.
Defensive Guidance
Patch. Update the .NET SDK to 1.71.0 and the Python SDK to 1.39.4. These are the minimum viable actions. Both updates are available on NuGet and PyPI respectively.
Audit your [KernelFunction] usage. Review every method in your codebase decorated with this attribute. Ask whether each one should be model-callable. Anything that touches the filesystem, network, database, or system processes deserves particular scrutiny. Remove the attribute from anything that was not explicitly designed and reviewed as an LLM-accessible tool.
Restrict AutoInvokeKernelFunctions. For agents handling sensitive operations, disable automatic function invocation and require human-in-the-loop confirmation before execution. The attack chain for CVE-2026-25592 depends on the agent invoking functions autonomously on injected instructions. Requiring human approval for function calls in high-privilege contexts breaks the chain.
Do not use InMemoryVectorStore in production. The component was flagged before these disclosures as unsuitable for production use. It has no access controls, no persistence guarantees, and, now, a patched-but-public RCE history. Use a dedicated vector database with proper authentication.
Treat LLM output as untrusted. Content processed by the model, whether from user input, RAG retrieval, or external tool results, should not flow into eval(), exec(), shell commands, or filesystem operations without explicit sanitization at the framework layer. No blocklist approach for eval() sanitization is reliable. The only safe approach is not using eval() with untrusted input.
Inspect ingested content for injection markers. RAG pipelines, email and document processing agents, and any agent that reads external content should include detection for prompt-injection patterns at the point of ingestion, before that content reaches the model context.
The Microsoft advisory and full technical writeups are available via the MSRC update guide and the Particula and PointGuard AI research posts referenced below.
References
- Microsoft MSRC — CVE-2026-25592 Security Advisory
- Microsoft MSRC — CVE-2026-26030 Security Advisory
- Particula — Semantic Kernel CVE-2026-25592: Arbitrary File Write via Exposed KernelFunction
- PointGuard AI — CVE-2026-26030: eval() RCE in Semantic Kernel InMemoryVectorStore and the Limits of Blocklists
- GitHub — mbanyamer/CVE-2026-26030-Microsoft-Semantic-Kernel-1.39.4-RCE (public PoC)
- Semantic Kernel Python SDK v1.39.4 release notes
- Semantic Kernel .NET SDK v1.71.0 release notes
Frequently Asked Questions
- What does an attacker need to exploit CVE-2026-25592?
- The attacker needs a route to inject content the agent will process — a crafted document, email, chat message, or RAG-retrieved text. No direct system access is required. The agent must be running the SessionsPythonPlugin and the exploited Semantic Kernel version. From there, the injected prompt directs the model to call the exposed DownloadFileAsync function with an attacker-controlled path, writing a payload to a startup or persistence location.
- Can CVE-2026-26030 be triggered via prompt injection, or does the attacker need to control user input directly?
- Both vectors work. If the application allows direct user input to flow into a vector store query, an attacker with application access can exploit it without prompt injection. In agentic contexts where the agent constructs its own filter queries based on retrieved or user-supplied context, prompt injection is sufficient. The injected prompt crafts a filter expression that escapes the lambda context and executes arbitrary code.
- Is there evidence of active exploitation of either CVE?
- No in-the-wild exploitation has been confirmed as of this publication. However, a public proof-of-concept for CVE-2026-26030 is available on GitHub (mbanyamer/CVE-2026-26030-Microsoft-Semantic-Kernel-1.39.4-RCE). Semantic Kernel is widely deployed in enterprise AI applications, so the attack surface is substantial. Patching should be treated as urgent rather than routine.