From 9deae53fb93f50e4f47fea322658cb302a4d07b3 Mon Sep 17 00:00:00 2001 From: Semgrep Autofix Date: Thu, 2 Apr 2026 08:02:28 +0000 Subject: [PATCH] fix unsafe annotation copying in llm_router decorator Prevent potential code injection via arbitrary type annotations in the llm_router decorator. ## Changes - Removed blanket copying of all annotations from decorated functions via `func.__annotations__.copy()` - Now only copies the return annotation when needed for validation - Added validation to ensure the annotation is an actual type object, not a string forward reference ## Why The previous code copied all annotations from user-provided decorated functions to the wrapper. String annotations (forward references) can be evaluated by `typing.get_type_hints()` in the function's globals/locals namespace, potentially executing arbitrary code. The fix restricts annotation copying to only the return type (which is actually used for routing validation) and rejects string annotations that could be dangerous when evaluated. The wrapper function already has proper parameter annotations defined in its signature, so those don't need to be copied. ## Semgrep Finding Details Annotations passed to `typing.get_type_hints` are evaluated in `globals` and `locals` namespaces. Make sure that no arbitrary value can be written as the annotation and passed to `typing.get_type_hints` function. @18578539 requested Semgrep Assistant generate this pull request to fix [a finding](https://semgrep.dev/orgs/rootflo_ai/findings/683091385) from the detection rule [python.lang.security.audit.dangerous-annotations-usage.dangerous-annotations-usage](https://semgrep.dev/r/python.lang.security.audit.dangerous-annotations-usage.dangerous-annotations-usage). --- flo_ai/flo_ai/arium/llm_router.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/flo_ai/flo_ai/arium/llm_router.py b/flo_ai/flo_ai/arium/llm_router.py index a70b4232..12c16761 100644 --- a/flo_ai/flo_ai/arium/llm_router.py +++ b/flo_ai/flo_ai/arium/llm_router.py @@ -1038,12 +1038,14 @@ async def wrapper( ): return await router_instance.route(memory, execution_context) - # Preserve the original function's type annotations including return type - wrapper.__annotations__ = func.__annotations__.copy() - - # Ensure the return annotation is properly set + # Only copy the return annotation if needed for validation + # Avoid copying arbitrary string annotations which could be evaluated + # by get_type_hints() and potentially execute code if 'return' in func.__annotations__: - wrapper.__annotations__['return'] = func.__annotations__['return'] + return_annotation = func.__annotations__['return'] + # Only copy if it's an actual type object, not a forward reference string + if not isinstance(return_annotation, str): + wrapper.__annotations__['return'] = return_annotation return wrapper