{"record":{"id":"931297c83eb06d5b","repo":"microsoft/semantic-kernel","slug":"access-to-attribute-node-attr-is-not-allowed-i","errorCode":null,"errorMessage":"Access to attribute '{node.attr}' is not allowed in filter expressions.","messagePattern":"Access to attribute '(.+?)' is not allowed in filter expressions\\.","errorType":"exception","errorClass":"VectorStoreOperationException","httpStatus":null,"severity":"error","filePath":"python/semantic_kernel/connectors/in_memory.py","lineNumber":161,"sourceCode":"    def _eval_Constant(self, node: ast.Constant, context: Mapping[str, Any]) -> Any:\n        \"\"\"Evaluate a constant literal.\"\"\"\n        del context\n        if isinstance(node.value, str) and len(node.value) > self._max_literal_collection_size:\n            raise VectorStoreOperationException(\n                \"String literals in filter expressions exceed the maximum allowed size.\"\n            )\n        return node.value\n\n    def _eval_Name(self, node: ast.Name, context: Mapping[str, Any]) -> Any:\n        \"\"\"Evaluate a variable reference.\"\"\"\n        if node.id not in context:\n            raise VectorStoreOperationException(f\"Use of name '{node.id}' is not allowed in filter expressions.\")\n        return context[node.id]\n\n    def _eval_Attribute(self, node: ast.Attribute, context: Mapping[str, Any]) -> Any:\n        \"\"\"Evaluate an attribute access.\"\"\"\n        if node.attr in self._blocked_attributes:\n            raise VectorStoreOperationException(\n                f\"Access to attribute '{node.attr}' is not allowed in filter expressions.\"\n            )\n        value = self.evaluate(node.value, context)\n        try:\n            return ReadOnlyAttributeDict._wrap_value(getattr(value, node.attr))\n        except AttributeError as e:\n            raise VectorStoreOperationException(\n                f\"Attribute '{node.attr}' is not available in filter expressions.\"\n            ) from e\n\n    def _eval_Subscript(self, node: ast.Subscript, context: Mapping[str, Any]) -> Any:\n        \"\"\"Evaluate an index or slice operation.\"\"\"\n        value = self.evaluate(node.value, context)\n        slice_value = self.evaluate(node.slice, context)\n        try:\n            return ReadOnlyAttributeDict._wrap_value(value[slice_value])\n        except Exception as e:\n            raise VectorStoreOperationException(f\"Error evaluating subscript access: {e}\") from e","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/connectors/in_memory.py#L143-L179","documentation":"_eval_Attribute first checks the attribute name against _blocked_attributes, a dunder/internal blocklist (e.g. __class__, __globals__, __subclasses__, __code__, __import__). Accessing any blocked attribute raises VectorStoreOperationException. The static parse walk also blocks these names with a more detailed message, so this runtime check is a defense-in-depth net for sandbox-escape attempts that bypass static validation.","triggerScenarios":"A filter that reaches the evaluator with an attribute access like x.__class__, x.__globals__, or x.__subclasses__ — normally caught at parse time; fires at eval only if the static blocked-attribute check was relaxed in a subclass.","commonSituations":"Adversarial or untrusted filter input attempting sandbox escape; subclassing InMemoryCollection and loosening blocked_filter_attributes; security testing of the filter sandbox.","solutions":["Do not reference dunder or internal attributes in filters.","Keep blocked_filter_attributes intact (do not remove entries when subclassing).","Treat any untrusted filter string as untrusted input; validate/author filters yourself rather than accepting raw user filters."],"exampleFix":"# before\nawait collection.search(vector=[...], options=VectorSearchOptions(filter=lambda x: x.__class__))  # blocked -> [1310]\n\n# after\nawait collection.search(vector=[...], options=VectorSearchOptions(filter=lambda x: x.category == 'a'))","handlingStrategy":"validation","validationCode":"import ast\n\ndef has_no_blocked_attrs(filter_str: str, blocked: set[str]) -> None:\n    for node in ast.walk(ast.parse(filter_str, mode='eval')):\n        if isinstance(node, ast.Attribute) and node.attr in blocked:\n            raise ValueError(f\"filter accesses blocked attribute '{node.attr}'\")","typeGuard":null,"tryCatchPattern":"from semantic_kernel.exceptions import VectorStoreOperationException\ntry:\n    await collection.search(vector=[...], options=opts)\nexcept VectorStoreOperationException:\n    # treat as untrusted input; do not loosen blocked_filter_attributes\n    raise","preventionTips":["Never reference dunder/internal attributes in filters.","Do not remove entries from blocked_filter_attributes when subclassing.","Treat externally supplied filter strings as untrusted."],"tags":["in-memory","filter","security","sandbox"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}