Skip to content
This repository was archived by the owner on Jun 16, 2026. It is now read-only.

Commit a569944

Browse files
Fix arbitrary code execution in dependency container. Restricted ast.Call resolution to a strict whitelist.
Co-authored-by: bashandbone <89049923+bashandbone@users.noreply.github.com>
1 parent 36fd381 commit a569944

2 files changed

Lines changed: 12 additions & 3 deletions

File tree

.jules/sentinel.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,8 @@
44
**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.
55
**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.
66
**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.
7+
8+
## 2026-04-22 - Arbitrary Code Execution via Unsafe AST Evaluation
9+
**Vulnerability:** Found a critical vulnerability in `_safe_eval_type` inside `src/codeweaver/core/di/container.py` where `ast.Call` nodes were unconditionally allowed during AST-based type string evaluation using Python's `eval()`. This allowed arbitrary callable execution within the module namespace.
10+
**Learning:** Even with an AST `NodeVisitor` ensuring restricted constructs (like disabling dunder access), unconditionally allowing `ast.Call` can be exploited to run system commands or unintended functions if an attacker controls a type annotation string.
11+
**Prevention:** Strictly enforce a whitelist for `ast.Call` validation checking `node.func.id` to match explicitly required dependencies (e.g., `Depends`, `depends`, `Field`, `PrivateAttr`, `Tag`). Avoid open-ended evaluations by enforcing an allow-only list of node types.

src/codeweaver/core/di/container.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,13 @@ def generic_visit(self, node: ast.AST) -> None:
111111
# - Unions: int | str (BinOp, BitOr)
112112
# - Annotated: Annotated[int, Depends(...)] (Call, keyword, Tuple, List)
113113
# - Literals: Literal["foo"] (Constant)
114-
if not isinstance(
114+
if isinstance(node, ast.Call):
115+
# Restricting arbitrary function calls during type evaluation prevents ACE vulnerabilities
116+
if not isinstance(node.func, ast.Name) or node.func.id not in {"Depends", "depends", "Field", "PrivateAttr", "Tag"}:
117+
raise TypeError(f"Forbidden function call in type string: {node.func.id if isinstance(node.func, ast.Name) else type(node.func).__name__}")
118+
elif isinstance(node, ast.keyword):
119+
pass
120+
elif not isinstance(
115121
node,
116122
(
117123
ast.Expression,
@@ -124,8 +130,6 @@ def generic_visit(self, node: ast.AST) -> None:
124130
ast.Load,
125131
ast.Tuple,
126132
ast.List,
127-
ast.Call,
128-
ast.keyword,
129133
),
130134
):
131135
raise TypeError(f"Forbidden AST node in type string: {type(node).__name__}")

0 commit comments

Comments
 (0)