refactor(core): Block __import__ via AST validation in native Python runner (#18974)

This commit is contained in:
Iván Ovejero
2025-09-01 09:47:15 +02:00
committed by GitHub
parent a8be824b57
commit 2c6e2f6c7e
2 changed files with 35 additions and 2 deletions

View File

@@ -11,6 +11,7 @@ from src.constants import (
ERROR_STDLIB_DISALLOWED,
ERROR_EXTERNAL_DISALLOWED,
ERROR_DANGEROUS_ATTRIBUTE,
ERROR_DYNAMIC_IMPORT,
ERROR_SECURITY_VIOLATIONS,
ALWAYS_BLOCKED_ATTRIBUTES,
UNSAFE_ATTRIBUTES,
@@ -56,7 +57,7 @@ class SecurityValidator(ast.NodeVisitor):
self.generic_visit(node)
def visit_Attribute(self, node: ast.Attribute) -> None:
"""Detect access to unsafe attributes that could bypass security."""
"""Detect access to unsafe attributes that could bypass security restrictions."""
if node.attr in UNSAFE_ATTRIBUTES:
# Block regardless of context
@@ -72,6 +73,35 @@ class SecurityValidator(ast.NodeVisitor):
self.generic_visit(node)
def visit_Call(self, node: ast.Call) -> None:
"""Detect calls to __import__() that could bypass security restrictions."""
is_import_call = (
# __import__()
(isinstance(node.func, ast.Name) and node.func.id == "__import__")
or
# builtins.__import__() or __builtins__.__import__()
(
isinstance(node.func, ast.Attribute)
and node.func.attr == "__import__"
and isinstance(node.func.value, ast.Name)
and node.func.value.id in {"builtins", "__builtins__"}
)
)
if is_import_call:
if (
node.args
and isinstance(node.args[0], ast.Constant)
and isinstance(node.args[0].value, str)
):
module_name = node.args[0].value
self._validate_import(module_name, node.lineno)
else:
self._add_violation(node.lineno, ERROR_DYNAMIC_IMPORT)
self.generic_visit(node)
# ========== Validation ==========
def _validate_import(self, module_path: str, lineno: int) -> None: