Skip to content

🛡️ Sentinel: [CRITICAL] Fix ACE vulnerability in safe type evaluation#366

Open
bashandbone wants to merge 1 commit into
mainfrom
sentinel/fix-ace-vuln-ast-call-16264884343887620784
Open

🛡️ Sentinel: [CRITICAL] Fix ACE vulnerability in safe type evaluation#366
bashandbone wants to merge 1 commit into
mainfrom
sentinel/fix-ace-vuln-ast-call-16264884343887620784

Conversation

@bashandbone

@bashandbone bashandbone commented May 27, 2026

Copy link
Copy Markdown
Contributor

🚨 Severity: CRITICAL
💡 Vulnerability: Arbitrary Code Execution (ACE) vulnerability found in src/codeweaver/core/di/container.py within the _safe_eval_type function. The function allowed generic ast.Call nodes inside type strings, which, when passed to eval(), permitted execution of any callable available in the module's global namespace.
🎯 Impact: An attacker or malicious configuration string could inject arbitrary code via unvalidated or manipulated string type annotations that get evaluated by the container.
🔧 Fix: Restrict ast.Call execution by verifying the function name (via node.func.id or node.func.attr) against a strict whitelist containing explicitly allowed callables ({"Depends", "depends", "Field", "PrivateAttr", "Tag"}). Added a comment explaining the fix.
Verification: Ran mise //:check for linting and formatting. Executed test suite targeting the modified file (tests/unit/core/di/test_container.py and tests/unit/core/di/test_container_phase1.py) and verified no regressions. Created a manual proof of concept script that confirmed the vulnerability and successfully verified the fix blocked execution.


PR created automatically by Jules for task 16264884343887620784 started by @bashandbone

Summary by Sourcery

Harden safe type evaluation in the DI container to eliminate an arbitrary code execution vector and document the security learning in Sentinel notes.

Bug Fixes:

  • Block arbitrary code execution in _safe_eval_type by restricting ast.Call nodes to a strict whitelist of allowed callables in type strings.

Documentation:

  • Extend Sentinel security log with details of the ACE vulnerability in _safe_eval_type, the root cause, and the prevention strategy.

- Identified that `_safe_eval_type` in `src/codeweaver/core/di/container.py` allowed generic `ast.Call` nodes.
- Fixed the Arbitrary Code Execution (ACE) vulnerability by verifying the `ast.Call` function names against a strict whitelist.
- Updated `.jules/sentinel.md` journal with critical learnings.
- Ensured formatting passes and tests successfully verify the fix.

Co-authored-by: bashandbone <89049923+bashandbone@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 27, 2026 17:43
@google-labs-jules

Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@sourcery-ai

sourcery-ai Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Tightens the container’s _safe_eval_type AST validator to disallow arbitrary ast.Call executions except for a small, explicit whitelist of DI-related helpers, and records the incident and remediation details in the Sentinel security log.

Flow diagram for _safe_eval_type ast.Call whitelist validation

flowchart LR
    A[type_str AST parsed] --> B[AstValidator.generic_visit node]
    B --> C{node is ast.Call?}
    C -- No --> D[super.generic_visit node]
    C -- Yes --> E{node.func is ast.Name?}
    E -- Yes --> F[func_name = node.func.id]
    E -- No --> G{node.func is ast.Attribute?}
    G -- Yes --> H[func_name = node.func.attr]
    G -- No --> I[raise TypeError Forbidden call representation]
    F --> J{func_name in whitelist?
    Depends
    depends
    Field
    PrivateAttr
    Tag}
    H --> J
    J -- No --> K[raise TypeError Forbidden callable in type string]
    J -- Yes --> D
    D --> L[eval type_str with validated AST]
Loading

File-Level Changes

Change Details Files
Harden AST validation in _safe_eval_type to prevent arbitrary code execution via type string evaluation.
  • Annotate _safe_eval_type definition with # noqa: C901 to suppress the function-complexity linter warning as logic becomes more involved.
  • Extend the AST visitor’s generic_visit to detect ast.Call nodes and extract the callable name from ast.Name or ast.Attribute, rejecting any other call representation.
  • Introduce a strict whitelist of allowed callables (Depends, depends, Field, PrivateAttr, Tag) and raise TypeError for calls outside this whitelist to block ACE vectors.
  • Preserve existing AST safety checks (e.g., for dunder attributes) while layering the new ast.Call restriction before delegating to super().generic_visit.
src/codeweaver/core/di/container.py
Document the newly discovered ACE vulnerability and its mitigation in the Sentinel security history.
  • Add a dated Sentinel entry describing the ACE via generic ast.Call in _safe_eval_type, including root cause, impact, and mitigation.
  • Capture the security learning that restricting __builtins__ is insufficient when eval() can still invoke global callables via allowed AST nodes.
  • Recommend explicit whitelisting of callables used in type evaluation as a prevention strategy for similar vulnerabilities.
.jules/sentinel.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@github-actions

Copy link
Copy Markdown
Contributor

🤖 Hi @bashandbone, I've received your request, and I'm working on it now! You can track my progress in the logs for more details.

@github-actions

Copy link
Copy Markdown
Contributor

🤖 I'm sorry @bashandbone, but I was unable to process your request. Please see the logs for more details.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • Consider extracting the hard-coded callable whitelist ({"Depends", "depends", "Field", "PrivateAttr", "Tag"}) into a named constant near the top of the module so it’s easier to reuse, audit, and extend in one place.
  • The _safe_eval_type method is now complex enough to trigger C901; if possible, factor the AST validation (including the ast.Call checks) into a dedicated helper/visitor class or function to keep _safe_eval_type focused on orchestration.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider extracting the hard-coded callable whitelist (`{"Depends", "depends", "Field", "PrivateAttr", "Tag"}`) into a named constant near the top of the module so it’s easier to reuse, audit, and extend in one place.
- The `_safe_eval_type` method is now complex enough to trigger `C901`; if possible, factor the AST validation (including the `ast.Call` checks) into a dedicated helper/visitor class or function to keep `_safe_eval_type` focused on orchestration.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the DI container’s string-based type evaluation to mitigate an Arbitrary Code Execution (ACE) vector introduced by permitting arbitrary ast.Call nodes to reach eval().

Changes:

  • Adds an ast.Call whitelist in Container._safe_eval_type() to restrict which callables may be invoked when evaluating type strings.
  • Documents the vulnerability, root cause, and prevention strategy in the Sentinel security log.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/codeweaver/core/di/container.py Restricts callable execution during safe type-string evaluation by validating ast.Call nodes against an allowlist.
.jules/sentinel.md Records the ACE finding and the mitigation approach in the security log.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +142 to +151
if isinstance(node, ast.Call):
if isinstance(node.func, ast.Name):
func_name = node.func.id
elif isinstance(node.func, ast.Attribute):
func_name = node.func.attr
else:
raise TypeError("Forbidden call representation in type string")

if func_name not in {"Depends", "depends", "Field", "PrivateAttr", "Tag"}:
raise TypeError(f"Forbidden callable in type string: {func_name}")
Comment on lines +139 to +143
# Restrict ast.Call to a strict whitelist to prevent Arbitrary Code Execution (ACE).
# Allowing generic ast.Call permits execution of any callable in the module's
# global namespace during eval(), introducing a critical ACE vulnerability.
if isinstance(node, ast.Call):
if isinstance(node.func, ast.Name):
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants