{"record":{"id":"a694d0b355bc3452","repo":"microsoft/semantic-kernel","slug":"access-to-attribute-node-attr-is-not-allowed-i-a694d0","errorCode":null,"errorMessage":"Access to attribute '{node.attr}' is not allowed in filter expressions. This attribute could be used to escape the filter sandbox.","messagePattern":"Access to attribute '(.+?)' is not allowed in filter expressions\\. This attribute could be used to escape the filter sandbox\\.","errorType":"exception","errorClass":"VectorStoreOperationException","httpStatus":null,"severity":"error","filePath":"python/semantic_kernel/connectors/in_memory.py","lineNumber":783,"sourceCode":"        lambda_node = tree.body\n        lambda_param_names = {arg.arg for arg in lambda_node.args.args}\n        lambda_param_order = [arg.arg for arg in lambda_node.args.args]\n        # Walk the AST to validate all nodes against the allowlist\n        for node_count, node in enumerate(ast.walk(tree), start=1):\n            if node_count > self.max_filter_ast_node_count:\n                raise VectorStoreOperationException(\"Filter expression exceeds the maximum allowed complexity.\")\n\n            node_type = type(node)\n\n            # Check if the node type is allowed\n            if node_type not in self.allowed_filter_ast_nodes:\n                raise VectorStoreOperationException(\n                    f\"AST node type '{node_type.__name__}' is not allowed in filter expressions.\"\n                )\n\n            # For Attribute nodes, validate that dangerous dunder attributes are not accessed\n            if 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            # For Name nodes, only allow the lambda parameter\n            if isinstance(node, ast.Name) and node.id not in lambda_param_names:\n                raise VectorStoreOperationException(\n                    f\"Use of name '{node.id}' is not allowed in filter expressions. \"\n                    f\"Only the lambda parameter(s) ({', '.join(lambda_param_names)}) can be used.\"\n                )\n\n            # For Call nodes, validate that only allowed functions are called\n            if isinstance(node, ast.Call):\n                func_name: str\n                if isinstance(node.func, ast.Name):\n                    func_name = node.func.id\n                elif isinstance(node.func, ast.Attribute):\n                    func_name = node.func.attr","sourceCodeStart":765,"sourceCodeEnd":801,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/connectors/in_memory.py#L765-L801","documentation":"Thrown by _parse_and_validate_filter (in_memory.py:782-785) when an Attribute node accesses a name in blocked_filter_attributes (dunders and introspection hooks such as __class__, __bases__, __mro__, __subclasses__, __globals__, __code__, __builtins__, __import__, __dict__, __reduce__, etc.). These attributes can be chained to escape the filter sandbox and execute arbitrary code, so they are rejected outright.","triggerScenarios":"A filter like `lambda x: x.__class__`, `lambda x: x.value.__globals__`, `lambda x: x.__class__.__bases__[0].__subclasses__()`, or any dunder traversal; also accidental access when a data field name happens to start with __.","commonSituations":"Attempting introspection in a filter; copy-pasting known Python sandbox-escape payloads; user-supplied/untrusted filter text; fields named with dunder prefixes.","solutions":["Never access dunder or internal attributes in filters; reference only real data fields.","If a field is genuinely named with a dunder prefix, rename it in the data model.","Treat all user-supplied filter strings as untrusted and run them through the preflight validator.","Do not attempt to relax blocked_filter_attributes; it exists to prevent code execution."],"exampleFix":"# before\nVectorSearchOptions(filter=\"lambda x: x.__class__.__name__ == 'Foo'\")  # sandbox escape\n# after\nVectorSearchOptions(filter=\"lambda x: x.type == 'Foo'\")                 # use a data field","handlingStrategy":"validation","validationCode":"import ast\n\nSAFE_NODES = {\n    ast.Expression, ast.Lambda, ast.arguments, ast.arg, ast.Compare, ast.BoolOp,\n    ast.UnaryOp, ast.And, ast.Or, ast.Not, ast.Eq, ast.NotEq, ast.Lt, ast.LtE,\n    ast.Gt, ast.GtE, ast.In, ast.NotIn, ast.Is, ast.IsNot, ast.Name, ast.Load,\n    ast.Attribute, ast.Subscript, ast.Slice, ast.Constant, ast.List, ast.Tuple,\n    ast.Set, ast.Dict, ast.BinOp, ast.Add, ast.Sub, ast.Mult, ast.Div, ast.Mod,\n    ast.FloorDiv, ast.Call,\n}\n\ndef preflight_filter(expr: str, *, max_len: int = 2048, max_nodes: int = 128) -> None:\n    if len(expr) > max_len:\n        raise ValueError(\"filter too long\")\n    try:\n        tree = ast.parse(expr, mode=\"eval\")\n    except SyntaxError as e:\n        raise ValueError(f\"invalid python: {e}\") from e\n    if not (isinstance(tree, ast.Expression) and isinstance(tree.body, ast.Lambda)):\n        raise ValueError(\"filter must be a lambda expression\")\n    blocked = {\"__class__\", \"__globals__\", \"__subclasses__\", \"__builtins__\", \"__code__\"}\n    for n in ast.walk(tree):\n        if isinstance(n, ast.Attribute) and n.attr in blocked:\n            raise ValueError(f\"blocked attribute: {n.attr}\")\n        if type(n) not in SAFE_NODES:\n            raise ValueError(f\"disallowed node: {type(n).__name__}\")\n    if sum(1 for _ in ast.walk(tree)) > max_nodes:\n        raise ValueError(\"filter too complex\")\n","typeGuard":null,"tryCatchPattern":"try:\n    results = await collection.search(search_type=SearchType.VECTOR, options=opts)\nexcept VectorStoreOperationException as e:\n    logger.warning(\"filter rejected: %s\", e.__cause__ or e)\n    results = None","preventionTips":["Treat filter strings as untrusted input; never accept them raw from end users.","Never access dunder attributes (__class__, __globals__, __subclasses__, etc.) in filters.","Run all string filters through the allowlist preflight before search.","Do not weaken blocked_filter_attributes to 'fix' a filter."],"tags":["filter","in-memory","security","sandbox","semantic-kernel"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}