From 9f2da6822a85320e73cd96ca39bcb3222612a389 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 2 Jun 2026 17:26:04 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[CRITICAL]?= =?UTF-8?q?=20Fix=20arbitrary=20code=20execution=20vulnerability=20in=20co?= =?UTF-8?q?ntainer=20type=20resolution?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added a strict whitelist for `ast.Call` nodes parsed inside `_safe_eval_type` before passing strings to `eval()` to prevent Arbitrary Code Execution (ACE) vulnerabilities. Modified `TypeValidator.generic_visit` to intercept `ast.Call` nodes and assert they map strictly to allowed known typing definitions (like `Depends`, `depends`, `Field`, `Parameter`, etc.), raising a TypeError for any unsupported function calls (e.g. system commands). Checked code with format, linting, and tests to ensure correctness. Co-authored-by: bashandbone <89049923+bashandbone@users.noreply.github.com> --- .jules/sentinel.md | 5 +++++ src/codeweaver/core/di/container.py | 26 +++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 1959a5253..0714626d3 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -4,3 +4,8 @@ **Vulnerability:** Found an unused `_attempt_import` function in `src/codeweaver/server/mcp/server.py` that dynamically imports a module directly from unvalidated configuration (`import_module(mw.rsplit(".", 1)[0])`), leading to potential arbitrary code execution. **Learning:** Functions that perform dynamic imports should not be left around in the codebase if they are unused, especially if they are designed to take unvalidated strings as input. **Prevention:** Avoid dynamic imports based on configuration or inputs without strict whitelisting. Use tools like `semgrep` with python security rules to actively catch these patterns. + +## 2026-04-22 - Arbitrary Code Execution (ACE) risk in type hint evaluation +**Vulnerability:** Found `ast.Call` nodes generically allowed in `_safe_eval_type` within `src/codeweaver/core/di/container.py`, meaning any arbitrary function callable in the namespace (like OS commands via `os.system` if imported) could be executed through malicious type strings parsed by `eval()`. +**Learning:** Even constrained restricted environments for `eval` cannot effectively sandbox `ast.Call` if `eval` dynamically evaluates parsed generic attributes. +**Prevention:** Always use an explicit whitelist matching exact function names (like `Depends`, `Field`, `Parameter`, etc.) rather than allowing all `ast.Call` structures to prevent unwanted arbitrary code execution during type resolution. diff --git a/src/codeweaver/core/di/container.py b/src/codeweaver/core/di/container.py index 7cd68ce98..a4d00ccd8 100644 --- a/src/codeweaver/core/di/container.py +++ b/src/codeweaver/core/di/container.py @@ -84,7 +84,7 @@ def __init__(self) -> None: self._request_cache: dict[Any, Any] = {} # Keys can be types or callables self._providers_loaded: bool = False # Track if auto-discovery has run - def _safe_eval_type(self, type_str: str, globalns: dict[str, Any]) -> Any | None: + def _safe_eval_type(self, type_str: str, globalns: dict[str, Any]) -> Any | None: # noqa: C901 """Safely evaluate a type string using AST validation. Parses the type string into an AST, validates that it contains only safe @@ -136,6 +136,30 @@ def generic_visit(self, node: ast.AST) -> None: if isinstance(node, ast.Attribute) and node.attr.startswith("__"): raise TypeError(f"Forbidden dunder attribute: {node.attr}") + # Security: Restrict arbitrary function execution in evaluate + if isinstance(node, ast.Call): + func_name = None + if isinstance(node.func, ast.Name): + func_name = node.func.id + elif isinstance(node.func, ast.Attribute): + func_name = node.func.attr + + allowed_funcs = { + "Depends", + "depends", + "Field", + "PrivateAttr", + "Tag", + "Parameter", + "AfterValidator", + "BeforeValidator", + "Discriminator", + "GetPydanticSchema", + "uuid7", + } + if func_name not in allowed_funcs: + raise TypeError(f"Arbitrary function calls are forbidden: {func_name}") + super().generic_visit(node) try: