
When Prompts Become Shells: RCE Vulnerabilities in AI Agent Frameworks (Semantic Kernel)
Microsoft discloses two CVEs in its Semantic Kernel AI agent framework: CVE-2026-26030, where AI-model-controlled input into an eval()-executed Python lambda filter (used by the In-Memory Vector Store's Search Plugin) bypasses an AST-based blocklist via class-hierarchy traversal to BuiltinImporter.load_module, achieving arbitrary code execution from a single injected prompt; and CVE-2026-25592, where the .NET SessionsPythonPlugin's DownloadFileAsync was accidentally exposed as a callable AI tool with an unsanitized file path, letting an attacker escape the Azure Container Apps sandbox and write a payload into the host's Startup folder for persistence/RCE. The post details the exploit chains (mapped to MITRE ATLAS AML.T0051→AML.T0016), Microsoft's four-layer AST allowlist fix and path-validation patch, affected version ranges, KQL hunting queries for post-exploitation detection, and a public CTF challenge to practice exploiting CVE-2026-26030.
What it is
Two CVEs in Microsoft Semantic Kernel, disclosed as part of a new Microsoft research series probing RCE paths in AI agent frameworks (Semantic Kernel, with LangChain/CrewAI flagged for future posts). CVE-2026-26030 is a Python eval() sandbox-escape in the In-Memory Vector Store's default filter function; CVE-2026-25592 is a .NET SessionsPythonPlugin method accidentally exposed as an AI-callable tool, enabling a sandbox escape from Azure Container Apps to the host.
How it works
CVE-2026-26030: The Search Plugin's default filter is built as a Python lambda string (e.g. lambda x: x.city == 'Paris') and run through eval(). The city value is AI-model-controlled and unsanitized, so closing the quote injects arbitrary logic. The framework's AST-based guard only checked ast.Name/ast.Attribute nodes against a blocklist (eval, exec, open, __import__, etc.) and stripped __builtins__. The disclosed bypass starts from tuple() — which needs no builtins — then walks Python's class hierarchy (__class__, __subclasses__-style traversal) to reach BuiltinImporter, calls load_module to pull in os, and invokes system(). None of __name__, load_module, system, or BuiltinImporter were on the blocklist, and the check never inspected ast.Subscript nodes, so bracket-notation access (obj['__class__']) would have been an alternate bypass even if names were blocked.
CVE-2026-25592: DownloadFileAsync in the .NET SDK was tagged with [KernelFunction], exposing it as an AI-invocable tool whose localFilePath parameter (passed straight to File.WriteAllBytes()) had no path validation. Chained with ExecuteCode (writes a payload inside the sandbox) and the exposed download tool (pulls that payload to an attacker-chosen host path), a single prompt injection sequence can place a script in the host's Windows\Start Menu\Programs\Startup folder, giving code execution on next sign-in — fully escaping the Azure Container Apps isolation boundary. The page also notes a reverse arbitrary-file-read issue: upload_file() in both SDKs took unvalidated local paths, letting injected prompts exfiltrate host files (e.g., SSH keys) into the sandbox.
flowchart LR
A[Prompt injection] --> B[ExecuteCode: write payload in sandbox]
B --> C[DownloadFileAsync: unsanitized localFilePath]
C --> D[Write to host Startup folder]
D --> E[Next sign-in: RCE on host]
F[Fix: remove KernelFunction attr] -.cuts chain at.-> CPreconditions / Affected
- CVE-2026-26030:
semantic-kernelPython package, version prior to 1.39.4, using the In-Memory Vector Store's filter functionality as the Search Plugin backend with default configuration, plus a prompt-injection vector into agent input. - CVE-2026-25592: Semantic Kernel .NET SDK older than 1.71.0 using
SessionsPythonPlugin.
What to do
- Upgrade Python
semantic-kernelto 1.39.4+ (no agent rewrite needed). - Upgrade the .NET SDK to 1.71.0+; this removes AI-model access to
DownloadFileAsync(the[KernelFunction]attribute was removed) and addsValidateLocalPathForDownload()usingPath.GetFullPath()canonicalization plus directory allowlisting for developers still calling it programmatically. - To check for prior exploitation, bound the "vulnerable window" (deployment of an affected version until patch) and hunt endpoint telemetry in that window. Two KQL queries are given against
DeviceProcessEvents: one flags Semantic Kernel–linked processes spawningcmd.exe,powershell.exe,certutil.exe,wscript.exe,bitsadmin.exe,nslookup.exe, etc.; the other filters specifically fordotnet.exeprocesses matchingsemantic[\s_\-]?kernel|SKAgent|kernel\.runspawning similar suspicious children. - A public CTF reproducing CVE-2026-26030 (the "hotel finder" agent, prompt-injection to
calc.exe) is available athttps://github.com/amiteliahu/AIAgentCTF/tree/main/CVE-2026-26030, explicitly for sandboxed/educational use only.
Caveats
The AST allowlist fix (node-type allowlist, function-call allowlist, dangerous-attribute blocklist, name-node restriction) is described as closing this specific exploit chain, but the post itself frames blocklist/allowlist approaches in dynamic languages as inherently fragile — it doesn't claim the fix is proven exhaustive against all eval-based bypasses, only that it eliminates the escape primitives used in the disclosed payload.
Organisations named here
- BuiltinImporter
CVEs named here
- CVE-2026-26030
- CVE-2026-25592
Technologies named here
- Microsoft Semantic Kernel
- Semantic Kernel
- LangChain
- CrewAI
- SessionsPythonPlugin
- Azure Container Apps dynamic sessions
- AIAgentCTF
- Microsoft Defender
- Copilot Studio Agent Builder
- .NET
- Python
- Azure
Techniques named here
- Prompt injection to tool-parameter code execution
- AML.T0051
- AML.T0016
- Unsafe string interpolation into eval
- AST blocklist bypass
- Sandbox escape via over-exposed helper function
- Arbitrary file read for exfiltration
- LLM Prompt Injection
- Obtain Capabilities
Related in AI Security
