microsoft/semantic-kernel · error · VectorStoreOperationException
Access to attribute '{node.attr}' is not allowed in filter e
Error message
Access to attribute '{node.attr}' is not allowed in filter expressions. This attribute could be used to escape the filter sandbox. What it means
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.
Source
Thrown at python/semantic_kernel/connectors/in_memory.py:783
lambda_node = tree.body
lambda_param_names = {arg.arg for arg in lambda_node.args.args}
lambda_param_order = [arg.arg for arg in lambda_node.args.args]
# Walk the AST to validate all nodes against the allowlist
for node_count, node in enumerate(ast.walk(tree), start=1):
if node_count > self.max_filter_ast_node_count:
raise VectorStoreOperationException("Filter expression exceeds the maximum allowed complexity.")
node_type = type(node)
# Check if the node type is allowed
if node_type not in self.allowed_filter_ast_nodes:
raise VectorStoreOperationException(
f"AST node type '{node_type.__name__}' is not allowed in filter expressions."
)
# For Attribute nodes, validate that dangerous dunder attributes are not accessed
if isinstance(node, ast.Attribute) and node.attr in self.blocked_filter_attributes:
raise VectorStoreOperationException(
f"Access to attribute '{node.attr}' is not allowed in filter expressions. "
"This attribute could be used to escape the filter sandbox."
)
# For Name nodes, only allow the lambda parameter
if isinstance(node, ast.Name) and node.id not in lambda_param_names:
raise VectorStoreOperationException(
f"Use of name '{node.id}' is not allowed in filter expressions. "
f"Only the lambda parameter(s) ({', '.join(lambda_param_names)}) can be used."
)
# For Call nodes, validate that only allowed functions are called
if isinstance(node, ast.Call):
func_name: str
if isinstance(node.func, ast.Name):
func_name = node.func.id
elif isinstance(node.func, ast.Attribute):
func_name = node.func.attrView on GitHub (pinned to c028a0c7dc)
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.
Example fix
# before VectorSearchOptions(filter="lambda x: x.__class__.__name__ == 'Foo'") # sandbox escape # after VectorSearchOptions(filter="lambda x: x.type == 'Foo'") # use a data field
Defensive patterns
Strategy: validation
Validate before calling
import ast
SAFE_NODES = {
ast.Expression, ast.Lambda, ast.arguments, ast.arg, ast.Compare, ast.BoolOp,
ast.UnaryOp, ast.And, ast.Or, ast.Not, ast.Eq, ast.NotEq, ast.Lt, ast.LtE,
ast.Gt, ast.GtE, ast.In, ast.NotIn, ast.Is, ast.IsNot, ast.Name, ast.Load,
ast.Attribute, ast.Subscript, ast.Slice, ast.Constant, ast.List, ast.Tuple,
ast.Set, ast.Dict, ast.BinOp, ast.Add, ast.Sub, ast.Mult, ast.Div, ast.Mod,
ast.FloorDiv, ast.Call,
}
def preflight_filter(expr: str, *, max_len: int = 2048, max_nodes: int = 128) -> None:
if len(expr) > max_len:
raise ValueError("filter too long")
try:
tree = ast.parse(expr, mode="eval")
except SyntaxError as e:
raise ValueError(f"invalid python: {e}") from e
if not (isinstance(tree, ast.Expression) and isinstance(tree.body, ast.Lambda)):
raise ValueError("filter must be a lambda expression")
blocked = {"__class__", "__globals__", "__subclasses__", "__builtins__", "__code__"}
for n in ast.walk(tree):
if isinstance(n, ast.Attribute) and n.attr in blocked:
raise ValueError(f"blocked attribute: {n.attr}")
if type(n) not in SAFE_NODES:
raise ValueError(f"disallowed node: {type(n).__name__}")
if sum(1 for _ in ast.walk(tree)) > max_nodes:
raise ValueError("filter too complex")
Try / catch
try:
results = await collection.search(search_type=SearchType.VECTOR, options=opts)
except VectorStoreOperationException as e:
logger.warning("filter rejected: %s", e.__cause__ or e)
results = None Prevention
- 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.
When it happens
Trigger: 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 __.
Common situations: Attempting introspection in a filter; copy-pasting known Python sandbox-escape payloads; user-supplied/untrusted filter text; fields named with dunder prefixes.
Related errors
- Access to attribute '{node.attr}' is not allowed in filter e
- Call target node type '{type(node.func).__name__}' is not al
- Filter string must be a lambda expression, e.g. 'lambda x: x
- AST node type '{node_type.__name__}' is not allowed in filte
- AST node type '{type(node).__name__}' is not supported durin
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/a694d0b355bc3452.
Report an issue: GitHub.