All posts
Unproven Execution

Semantic Kernel CVEs: Unproven Execution by Default

Microsoft disclosed two RCE flaws in Semantic Kernel where framework defaults exposed code-execution sinks to prompt-injected LLM agents

Securityv0 Intelligence Team OWASP: ASI05 sv0 finding: unproven_execution
semantic-kernel microsoft llm-agent prompt-injection unproven-execution asi05

The Incident

On 2026-05-07, Microsoft published a coordinated retrospective on two prompt-injection-to-RCE vulnerabilities in Semantic Kernel, its open-source agent framework. CVE-2026-26030 (CVSS 9.9, CWE-94) affected the Python SDK’s InMemoryVectorStore filter, which fed an LLM-influenced filter expression into eval() inside a generated lambda; CVE-2026-25592 (CVSS 9.9, CWE-22) affected the .NET SDK’s SessionsPythonPlugin, where DownloadFileAsync and UploadFileAsync accepted attacker-controlled paths and were reachable from the model as [KernelFunction]-decorated tools. The Python flaw is patched in semantic-kernel 1.39.4 and the .NET flaw in Microsoft.SemanticKernel.Plugins.Core 1.71.0; the GitHub Security Advisories (GHSA-xjw9-4gw8-4rqx and GHSA-2ww3-72rp-wpp4) were published 2026-02-19 and 2026-02-06, with discovery credited to doredry, amiteliahu, and urioren.

The Python exploit chains a classic Python sandbox escape: a prompt-injected filter string walks ().__class__.__bases__[0].__subclasses__() to reach BuiltinImporter and from there os.system, executing arbitrary commands in the host process running the agent. The .NET exploit uses the path-traversal sink directly: a prompt that asks the agent to “save this file” can write attacker-controlled content into the host filesystem, including the user’s Startup folder, achieving persistence on the next login. There is no public evidence of in-the-wild exploitation; both findings were responsibly disclosed and patched before the May write-up.

MITRE ATT&CK coverage: T1059.006 (Command and Scripting Interpreter: Python), T1547.001 (Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder), T1059 (Command and Scripting Interpreter).

The Authority Path That Failed

The identity carrying execution authority at the moment of failure is the Semantic Kernel agent process — a non-human identity running with the host application’s full OS, filesystem, and network permissions. In CVE-2026-25592, the agent held every method the SDK had decorated [KernelFunction] plus whatever the host permitted; it exercised a write into the user’s Startup folder because DownloadFileAsync was advertised to the model as a callable tool with no path canonicalization or directory allowlist. In CVE-2026-26030, the agent held permission to evaluate filter strings inside its own Python process; it exercised eval() on an attacker-shaped expression because the default InMemoryVectorStore filter treated user-influenced strings as code, not data.

The trust anchor that failed first in both CVEs is the framework default. [KernelFunction] is a one-way gate from “internal helper” to “model-callable tool” with no second authorization layer between the developer’s annotation and the LLM’s reach. The Python filter pipeline assumes a “filter expression” is a benign DSL, not an eval argument. In each case, the gap between held scope (everything the host process can do) and exercised scope (write to Startup, spawn a shell) was statically inspectable: a tool registry diff would have shown DownloadFileAsync becoming model-callable, and a code-execution-sink inventory would have flagged a default-on plugin path that routed user input into eval.

SecurityV0 Perspective

This fits unproven_execution / ASI05. The defect is not that prompt injection happened; it is that the framework attached code-execution and filesystem-write tools to the agent that the deploying operator never explicitly authorized. The Microsoft fix patches the two specific sinks. The pattern — framework defaults that promote internal helpers into model-callable tools — outlasts the CVEs.

The evidence pack for this finding would enumerate, per Semantic Kernel agent in the environment: every [KernelFunction]-decorated method reachable from the model, the source file and commit that introduced the decorator, the host-process identity under which the agent runs, every default-loaded plugin whose code path routes user-influenced input into a code-execution sink (eval, exec, Invoke, dynamic loaders), and the package hash of each Semantic Kernel artifact. Before exfiltration, that pack answers: which [KernelFunction]s does this agent expose today, and did anyone explicitly approve them? After the fact, it answers the forensic question: which model calls reached which decorated method during the exposure window, with what arguments, and against which version of the SDK?

What To Do

  • Upgrade and pin Semantic Kernel to the patched releases. Move every Python deployment to semantic-kernel 1.39.4 or later (CVE-2026-26030) and every .NET deployment to Microsoft.SemanticKernel.Plugins.Core 1.71.0 or later (CVE-2026-25592). Pin exact versions in your lock files; do not rely on a floating minor-version range to pull the patch.
  • Inventory every [KernelFunction] your agents expose. Walk each agent’s plugin registration code and produce a list of the methods the SDK has advertised to the model — file path, commit, parameter types, and whether path or shell input is involved. Treat any decorated method that touches the filesystem, process spawning, or network outbound as model-callable until proven otherwise.
  • Block default code-execution sinks in agent data paths. Audit any plugin that routes user-influenced strings into eval, exec, Invoke, dynamic class loading, or template engines that execute. The Python InMemoryVectorStore filter pattern is one example; comparable defaults exist across other agent frameworks. Replace dynamic evaluation with parsed AST whitelists or static dispatch.
  • Run agents under a dedicated low-privilege OS identity. A Semantic Kernel host that loads third-party plugins should not run with cloud credentials, production tokens, write access to the user’s Startup folder, or filesystem reach beyond its stated function. Move long-lived secrets out of the agent’s environment and into per-call, scope-limited issuers.
  • Alert on [KernelFunction] registry diffs and eval-adjacent sink calls. Per-build baselines of which methods are [KernelFunction]-decorated, plus EDR rules that flag python.exe (or dotnet.exe) child processes spawning shells under a Semantic Kernel parent, turn novel tool exposure into actionable signal. A new decorated method appearing in a release diff should require operator review, not implicit acceptance.

Sources