NAS
DIGITAL
Our Work Blog Bespoke Websites Shop NAS Finds Say Hello →

Shop

  • Gumroad
  • PromptBase
  • Itch.io
  • Patreon
  • Ko-Fi

Follow

  • Twitter
  • Instagram
  • TikTok
  • YouTube
  • LinkedIn
  • GitHub
  • Mastodon
  • Facebook

Topics

  • AI & Automation
  • Security & Privacy
  • Development
  • Tools & Templates
  • Design & Creative
  • Productivity
  • Web Design
  • Business
  • Game Development
  • Writing & Content
  • Industry Trends
  • Tutorials
Latest Articles

From our desk.

Your Semantic Kernel Agent Has a CVSS 10.0 Vulnerability — And the Patch Doesn't Fully Fix It

June 9, 2026 Security & Privacy

On 7 May 2026, Microsoft quietly disclosed two critical vulnerabilities in Semantic Kernel — the official .NET framework that tens of thousands of enterprise developers are using to build AI agents right now. One of them is rated CVSS 10.0. The official patch in version 1.71.0 addresses the specific vulnerability, but independent security research has found six ways around it. This post explains what the vulnerability actually is, how it works against a real .NET application, what the bypass vectors look like, and what you actually need to do to be safe...

What is Semantic Kernel and Why Does This Matter

Semantic Kernel is Microsoft's open-source .NET framework for building AI agents. If you're connecting an LLM to your enterprise systems — Azure SQL databases, SharePoint, internal APIs, file systems — there's a very good chance you're using it or will be soon. It has over 27,000 GitHub stars and is the recommended Microsoft path for enterprise AI development.

The framework works by exposing your code to the AI through a system of "kernel functions" — methods decorated with [KernelFunction] that the LLM can invoke when it decides it needs them. This is powerful. It is also, if done carelessly, catastrophic.

CVE-2026-25592: The Sandbox That Wasn't

The SessionsPythonPlugin in SK's .NET SDK exists to let agents execute Python code inside an Azure Container Apps sandbox. The idea is that the sandbox isolates any code the agent runs from your host machine.

The vulnerability is simple. A helper method called DownloadFileAsync — designed to move files from the sandbox to the host — was accidentally tagged with [KernelFunction]. That single attribute exposed the method to the LLM as a callable tool.

Once that happened, the localFilePath parameter became AI-controlled. An attacker who can influence any prompt the agent reads — a support ticket, a document in your RAG index, a user message — can make the agent call DownloadFileAsync with a path of their choosing and write a file anywhere on the host filesystem.

Combine that with a write to the Windows Startup folder, and the next login is a payload execution. Full remote code execution. No authentication required. No network position required beyond reaching the agent.

Here's what the vulnerable pattern looks like in practice:

// THIS IS THE VULNERABLE PATTERN - pre-1.71.0
// DownloadFileAsync was exposed as a KernelFunction with
// no path validation on localFilePath
// An attacker-controlled prompt can invoke this with:
// localFilePath = "C:\\Users\\[user]\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\evil.exe"

And here's the correct hardened pattern you should be using regardless of which version you're on:

// HARDENED APPROACH
// 1. Disable AutoInvokeKernelFunctions on agents with disk or shell access
var executionSettings = new OpenAIPromptExecutionSettings
{
    ToolCallBehavior = ToolCallBehavior.EnableKernelFunctions
    // NOT ToolCallBehavior.AutoInvokeKernelFunctions
};

// 2. If you must use AutoInvoke, validate ALL path parameters in KernelFunctions
[KernelFunction]
public async Task<string> DownloadFileAsync(string localFilePath)
{
    // Anchor to an allowlisted directory - never trust AI-supplied paths
    var allowedRoot = Path.GetFullPath("/app/downloads");
    var requestedPath = Path.GetFullPath(
        Path.Combine(allowedRoot, Path.GetFileName(localFilePath))
    );

    if (!requestedPath.StartsWith(allowedRoot, StringComparison.OrdinalIgnoreCase))
    {
        throw new SecurityException(
            $"Path traversal attempt detected: {localFilePath}"
        );
    }

    // proceed with validated path
}

// 3. Add a Function Invocation Filter to audit all AI-triggered calls
kernel.FunctionInvocationFilters.Add(new SecurityAuditFilter());

public class SecurityAuditFilter : IFunctionInvocationFilter
{
    public async Task OnFunctionInvocationAsync(
        FunctionInvocationContext context,
        Func<FunctionInvocationContext, Task> next)
    {
        // Log every AI-triggered function call with full argument capture
        // Alert on any function accessing filesystem, network, or database
        var sensitiveFunction = context.Function.Name.Contains("File") ||
                                context.Function.Name.Contains("Download") ||
                                context.Function.Name.Contains("Execute");

        if (sensitiveFunction)
        {
            // Log to your security audit trail
            await LogSecurityEvent(context);
        }

        await next(context);
    }
}

Why the Official Patch Doesn't Fully Protect You

Upgrading to 1.71.0 addresses the specific DownloadFileAsync exposure. But independent security research has identified that the root cause — the framework treating LLM output as trusted system commands — creates an entire class of similar vulnerabilities that the patch doesn't address.

The patch added path validation to the specific method that was reported. It didn't add a systemic control preventing AI-controlled values from reaching filesystem operations in other functions. If you have any custom [KernelFunction] implementations that accept path, URL, or query parameters and pass them to system operations, you have the same class of vulnerability regardless of your SK version.

The right question to ask is not "am I on 1.71.0?" It's "do I have any [KernelFunction] methods that accept parameters from the AI and pass them to privileged operations without an allowlist?"

The Second Broken Control: RequireUserConfirmation

While you're auditing your implementation, check this too.

RequireUserConfirmation is the flag SK provides for human-in-the-loop safety. The idea is that before the agent takes a dangerous action, it pauses and asks a human to approve. Many enterprise implementations list this as their safety control for high-risk operations.

A confirmed open issue in the SK GitHub repository shows it doesn't work. It bypasses when it should fire. It silently hangs when explicitly disabled. If your threat model includes "we'll add human confirmation for anything destructive," that control is currently not functioning as documented.

Until this is resolved in the framework, you need an explicit wrapper:

// Don't rely on RequireUserConfirmation
// Implement explicit confirmation at the application layer
public class ConfirmationRequiredFilter : IFunctionInvocationFilter
{
    private readonly IConfirmationService _confirmationService;

    public async Task OnFunctionInvocationAsync(
        FunctionInvocationContext context,
        Func<FunctionInvocationContext, Task> next)
    {
        var requiresConfirmation = context.Function
            .Metadata.AdditionalProperties
            .TryGetValue("RequiresHumanApproval", out _);

        if (requiresConfirmation)
        {
            var approved = await _confirmationService
                .RequestApprovalAsync(context.Function.Name, context.Arguments);

            if (!approved)
                throw new OperationCanceledException("Human approval denied.");
        }

        await next(context);
    }
}

The Three-Point Security Baseline for Semantic Kernel Applications

If you take nothing else from this, implement these three things:

  1. Disable AutoInvokeKernelFunctions on any agent with access to the filesystem, network, or database. Enable it only for strictly read-only, idempotent operations. For everything else, require explicit invocation.

  2. Every [KernelFunction] that accepts a path, URL, query, or command parameter needs an allowlist validation before that parameter reaches any system call. Don't validate what's disallowed — validate what's allowed.

  3. Add a FunctionInvocationFilter that logs every AI-triggered function call to your security audit trail. If you don't know what your agent is invoking, you can't detect when it's been compromised.


View templates and tools on Gumroad →

Get in Touch

Got an idea? Want something custom?

We love hearing from people. Whether it's a custom commission, a bulk licence, or just a question about a product — drop us an email and we'll get back to you, usually within a day.

[email protected]
NAS DIGITAL · NEW HOLLAND, LINCOLNSHIRE · 2026 Made with care · Always improving