{"repro_id":"REPRO-2026-00099","version":5,"title":"Semantic Kernel: RCE via InMemoryVectorStore Filter","repro_type":"security","status":"published","severity":"critical","description":"An RCE vulnerability has been identified in Microsoft Semantic Kernel Python SDK, specifically within the `InMemoryVectorStore` filter functionality.","root_cause":"# Root Cause Analysis Report\n## GHSA-xjw9-4gw8-4rqx: Microsoft Semantic Kernel InMemoryVectorStore RCE\n\n## Summary\n\nThe Microsoft Semantic Kernel Python SDK contains a critical Remote Code Execution (RCE) vulnerability in its `InMemoryVectorStore` filter functionality. The vulnerability allows attackers to escape the filter sandbox by accessing Python's dunder (double underscore) attributes such as `__class__`, `__bases__`, `__subclasses__`, `__mro__`, `__dict__`, and `__getattribute__` within filter expressions. These attributes can be chained together to traverse Python's object hierarchy and gain access to sensitive classes and functions, potentially leading to arbitrary code execution.\n\n## Impact\n\n**Package:** semantic-kernel (Python SDK)\n**Affected Versions:** < 1.39.4\n**Fixed Version:** 1.39.4\n**Risk Level:** CRITICAL (CVSS 10.0)\n\n**Consequences:**\n- An attacker can escape the filter sandbox and execute arbitrary Python code\n- The vulnerability can be triggered through user-controlled filter expressions\n- Complete system compromise is possible through Python's introspection capabilities\n- The InMemoryVectorStore is not recommended for production use, but this vulnerability affects any application using it for testing or development\n\n## Root Cause\n\nThe vulnerability exists in the `_parse_and_validate_filter` method in `python/semantic_kernel/connectors/in_memory.py`. The method uses an allowlist approach to validate AST (Abstract Syntax Tree) nodes and function calls in filter expressions, but it fails to validate `ast.Attribute` nodes for dangerous attribute names.\n\n### Technical Details:\n\n1. The filter parser walks the AST and validates:\n   - Node types against `allowed_filter_ast_nodes` (which includes `ast.Attribute`)\n   - Name nodes against lambda parameter names\n   - Function calls against `allowed_filter_functions`\n\n2. **Missing validation:** The code does NOT check if `ast.Attribute` nodes access dangerous dunder attributes like:\n   - `__class__` - Access to object's class\n   - `__bases__` - Access to base classes\n   - `__subclasses__` - Access to all subclasses of a class\n   - `__mro__` - Method Resolution Order (object hierarchy)\n   - `__dict__` - Access to object's attributes\n   - `__getattribute__` - Access to attribute retrieval method\n\n3. **Exploitation chain:** An attacker can chain these attributes to traverse from a simple data object to the root `object` class, enumerate all loaded classes via `__subclasses__()`, and find classes that expose dangerous functionality (like `warnings.catch_warnings` which can execute arbitrary code).\n\n### Fix:\n\nThe fix (PR #13505) adds a `blocked_filter_attributes` set containing dangerous attribute names and validates all `ast.Attribute` nodes against this blocklist:\n\n```python\n# For Attribute nodes, validate that dangerous dunder attributes are not accessed\nif isinstance(node, ast.Attribute) and node.attr in self.blocked_filter_attributes:\n    raise VectorStoreOperationException(\n        f\"Access to attribute '{node.attr}' is not allowed in filter expressions. \"\n        \"This attribute could be used to escape the filter sandbox.\"\n    )\n```\n\n## Reproduction Steps\n\nThe reproduction script is located at `repro/reproduction_steps.sh`.\n\n### What the script does:\n\n1. Creates a Python virtual environment\n2. Installs the vulnerable semantic-kernel version 1.39.3\n3. Creates an InMemoryVectorStore with a test collection\n4. Tests various filter expressions that access dangerous dunder attributes:\n   - `lambda x: x.__class__.__name__ == 'TestDataModel'`\n   - `lambda x: x.__class__.__base__ is not None`\n   - `lambda x: x.__class__.__mro__ is not None`\n   - `lambda x: x.__dict__ is not None`\n   - `lambda x: x.__getattribute__ is not None`\n   - `lambda x: x.__class__.__bases__ is not None`\n\n### Expected evidence of reproduction:\n\nAll tests pass in the vulnerable version, demonstrating that dangerous dunder attributes can be accessed without restriction. The output shows:\n\n```\n[+] Test 1 PASSED: Filter with __class__ executed: True\n[+] Test 2 PASSED: Filter with __base__ executed: True\n[+] Test 3 PASSED: Filter with __mro__ executed: True\n[+] Test 4 PASSED: Filter with __dict__ executed: True\n[+] Test 5 PASSED: Filter with __getattribute__ executed: True\n[+] Test 6 PASSED: Filter with __bases__ executed: True\n[+] Test 7 PASSED: Filter with method access executed: True\n```\n\n## Evidence\n\n**Log location:** `$ROOT/logs/` (created by reproduction script)\n\n**Key excerpts from reproduction:**\n\nThe script confirmed that in semantic-kernel 1.39.3, the following dangerous filter expressions execute successfully:\n\n1. `lambda x: x.__class__.__name__ == 'TestDataModel'` - Access to `__class__` attribute\n2. `lambda x: x.__class__.__base__ is not None` - Access to `__base__` attribute\n3. `lambda x: x.__class__.__mro__ is not None` - Access to `__mro__` attribute\n4. `lambda x: x.__dict__ is not None` - Access to `__dict__` attribute\n5. `lambda x: x.__getattribute__ is not None` - Access to `__getattribute__` attribute\n6. `lambda x: x.__class__.__bases__ is not None` - Access to `__bases__` attribute\n\n**Environment details:**\n- Python 3.11\n- semantic-kernel 1.39.3 (vulnerable)\n- pydantic (dependency)\n- numpy (dependency)\n- scipy (dependency)\n\n## Recommendations / Next Steps\n\n### Immediate Actions:\n\n1. **Upgrade to semantic-kernel 1.39.4 or later** - This version contains the fix that blocks dangerous dunder attributes in filter expressions.\n\n2. **Avoid using InMemoryVectorStore in production** - Microsoft already recommends against using InMemoryVectorStore for production scenarios. Use a proper vector database instead (Azure AI Search, Redis, PostgreSQL with pgvector, etc.)\n\n3. **Review existing code** - Check if any existing code uses string-based filters with the InMemoryVectorStore. If so, ensure the semantic-kernel version is upgraded.\n\n### Testing Recommendations:\n\n1. **Verify the fix** - After upgrading, test that filter expressions with blocked attributes raise `VectorStoreOperationException`:\n   ```python\n   # This should raise an exception after the fix\n   filter_str = \"lambda x: x.__class__.__name__ == 'TestDataModel'\"\n   ```\n\n2. **Regression tests** - Ensure legitimate filter expressions still work:\n   ```python\n   # These should continue to work\n   filter_str = \"lambda x: x.content == 'test'\"\n   filter_str = \"lambda x: x.id.startswith('prefix')\"\n   ```\n\n### Long-term Recommendations:\n\n1. **Input validation** - Never pass user-controlled or LLM-generated filter strings directly to the InMemoryVectorStore without strict validation.\n\n2. **Security review** - Conduct security reviews of any code using dynamic filter expressions.\n\n## Additional Notes\n\n### Idempotency Confirmation:\n\nThe reproduction script is idempotent and passes two consecutive runs:\n- First run: Installs dependencies and confirms vulnerability\n- Second run: Reuses virtual environment, still confirms vulnerability\n\n### Edge Cases:\n\n1. **Fixed version behavior** - In semantic-kernel 1.39.4+, attempting to use blocked attributes in filter expressions will raise:\n   ```\n   VectorStoreOperationException: Access to attribute '__class__' is not allowed in filter expressions. This attribute could be used to escape the filter sandbox.\n   ```\n\n2. **Partial RCE chains** - While the reproduction demonstrates access to dangerous attributes, a full RCE chain would require additional steps to find and invoke a class that executes arbitrary code. The vulnerable version allows these chains; the fixed version blocks them at the attribute access level.\n\n### References:\n\n- GitHub Advisory: https://github.com/advisories/GHSA-xjw9-4gw8-4rqx\n- CVE: CVE-2026-26030\n- Fix PR: https://github.com/microsoft/semantic-kernel/pull/13505\n- Release: https://github.com/microsoft/semantic-kernel/releases/tag/python-1.39.4\n","ghsa_id":"GHSA-xjw9-4gw8-4rqx","cve_id":"CVE-2026-26030","cwe_id":"CWE-94 (Code Injection)","package":{"name":"semantic-kernel","ecosystem":"pip","affected_versions":"< 1.39.4","fixed_version":"1.39.4","tested_patched":"1.39.4"},"reproduced_at":"2026-02-19T21:13:51.862228+00:00","duration_secs":1513.482828617096,"tool_calls":114,"turns":89,"handoffs":2,"total_cost_usd":0.5510406999999998,"agent_costs":{"repro":0.30642469999999994,"support":0.0348978,"vuln_variant":0.2097182},"cost_breakdown":{"repro":{"accounts/fireworks/models/kimi-k2p5":0.30642469999999994},"support":{"accounts/fireworks/models/kimi-k2p5":0.0348978},"vuln_variant":{"accounts/fireworks/models/kimi-k2p5":0.2097182}},"quality":{"idempotent_verified":false,"community_verifications":0},"published_at":"2026-02-19T21:13:53.658473+00:00","retracted":false,"artifacts":[{"path":"repro/rca_report.md","filename":"rca_report.md","size":7835,"category":"analysis"},{"path":"repro/reproduction_steps.sh","filename":"reproduction_steps.sh","size":6495,"category":"reproduction_script"},{"path":"bundle/ticket.md","filename":"ticket.md","size":1801,"category":"ticket"},{"path":"bundle/source.json","filename":"source.json","size":6303,"category":"other"},{"path":"bundle/ticket.json","filename":"ticket.json","size":8826,"category":"other"},{"path":"logs/test_variant_1.39.4.py","filename":"test_variant_1.39.4.py","size":7750,"category":"script"},{"path":"logs/variant_test_1.39.4.log","filename":"variant_test_1.39.4.log","size":5000,"category":"log"},{"path":"logs/variant_test_1.39.3.log","filename":"variant_test_1.39.3.log","size":3743,"category":"log"},{"path":"logs/test_variant_1.39.3.py","filename":"test_variant_1.39.3.py","size":7750,"category":"script"}]}