Skip to main content

eval/exec Wrapper

FieldValue
Document IDASCEND-SDK-013
Version2026.04
Last UpdatedApril 2026
AuthorAscend Engineering Team
PublisherOW-KAI Technologies Inc.
ClassificationEnterprise Client Documentation
ComplianceSOC 2 CC6.1/CC6.2, PCI-DSS 7.1/8.3, HIPAA 164.312, NIST 800-53 AC-2/SI-4

Governed dynamic code execution for AI agents.

Overview​

The ASCEND eval/exec wrapper provides safe alternatives to Python's eval() and exec() functions with 4-layer defense: AST analysis, governance check, sandboxed execution, and timeout protection.

danger

The eval/exec wrapper governs dynamic code execution. Never use Python's native eval() or exec() in AI agent code -- always use safe_eval and safe_exec to ensure governance evaluation and sandboxing.

Installation​

from ascend.wrappers.dynamic_code import safe_eval, safe_exec, SafeEvaluator

Features​

  • 4-layer defense - Length check, AST analysis, governance, sandbox
  • Restricted builtins - Only safe functions allowed
  • Timeout protection - Prevents infinite loops (Unix SIGALRM)
  • AST-based analysis - Detects dangerous constructs before execution
  • Fail-closed by default - Denies on any error
  • Configurable allow/block lists - Whitelist approach

Usage​

Basic Usage​

from ascend.wrappers.dynamic_code import safe_eval, safe_exec

# Safe expression evaluation
result = safe_eval("2 + 2") # Returns 4

# With context variables
result = safe_eval("price * quantity", {"price": 10, "quantity": 5}) # Returns 50

# Safe code execution (returns created variables)
namespace = safe_exec("x = 10; y = x * 2")
print(namespace["y"]) # 20

With SafeEvaluator Class​

from ascend.wrappers.dynamic_code import SafeEvaluator

evaluator = SafeEvaluator(
client=ascend_client, # ASCEND client for governance
allowed_builtins={"sum", "len", "min", "max"}, # Restrict builtins
max_code_length=10000, # Max code size
timeout_seconds=5 # Execution timeout
)

result = evaluator.eval("sum([1, 2, 3])") # Returns 6

# Analyze without executing
analysis = evaluator.analyze("import os; os.system('ls')")
print(analysis.is_safe) # False
print(analysis.reason) # "Import statement not allowed: os"

4-Layer Defense Model​

User Code Input
│
▼
┌─────────────────────┐
│ Layer 0: Length │ Code length <= max_code_length (default: 10000)
│ Check │
└─────────────────────┘
│
▼
┌─────────────────────┐
│ Layer 1: AST │ Parse and analyze syntax tree
│ Analysis (Local) │ - Detect imports
│ │ - Detect dangerous calls (eval, exec, __import__)
│ │ - Detect sandbox escape (__class__, __bases__)
│ │ - Detect file/network operations
└─────────────────────┘
│
▼
┌─────────────────────┐
│ Layer 2: Governance │ Submit to ASCEND (if client configured)
│ Check (Remote) │ - action_type="code.eval" or "code.exec"
│ │ - Include AST findings count
└─────────────────────┘
│
▼
┌─────────────────────┐
│ Layer 3: Sandbox │ Restricted execution environment
│ Execution │ - Only allowed builtins
│ │ - No __builtins__ access
│ │ - Context variables only
└─────────────────────┘
│
▼
┌─────────────────────┐
│ Layer 4: Timeout │ Unix SIGALRM timeout protection
│ Protection │ - Default: 5 seconds
└─────────────────────┘
│
▼
Result

AST Analysis Categories​

The analyzer detects dangerous constructs in these categories:

Code Injection (Critical)​

PatternDescription
eval()Dynamic evaluation
exec()Dynamic execution
compile()Code compilation
__import__()Dynamic import
import ...Import statements
from ... importFrom imports
getattr/setattr/delattrAttribute manipulation
globals/locals/varsNamespace access

Sandbox Escape (Critical)​

PatternDescription
__class__Class access
__bases__Base class access
__mro__Method resolution order
__subclasses__Subclass enumeration
__globals__Global namespace
__builtins__Builtins access
__code__Code object access
__closure__Closure access
__dict__Dictionary access

File Access (High)​

PatternDescription
open()File open
read()File read
write()File write

Network Access (High)​

PatternDescription
socketSocket module
urllibURL library
requestsHTTP library
httpxHTTP library
aiohttpAsync HTTP

Default Safe Builtins​

The following builtins are allowed by default:

DEFAULT_SAFE_BUILTINS = {
# Math
"abs", "round", "min", "max", "sum", "pow", "divmod", "float", "int",

# Data structures
"len", "list", "dict", "set", "tuple", "frozenset",
"str", "bool", "bytes", "bytearray",

# Iteration
"range", "enumerate", "zip", "map", "filter", "sorted", "reversed",

# Type checking
"type", "isinstance", "issubclass",

# Other safe operations
"all", "any", "repr", "hash", "id", "ord", "chr", "bin", "hex", "oct",
}

SafeEvaluator Class​

from ascend.wrappers.dynamic_code import SafeEvaluator

evaluator = SafeEvaluator(
client=None, # AscendClient for governance
fail_mode="closed", # 'closed' or 'open'
allowed_builtins={"len", "sum"}, # Override defaults
blocked_names={"custom_func"}, # Additional blocked names
max_code_length=10000, # Max code size
timeout_seconds=5, # Execution timeout
allow_imports=False # Allow imports (default: False)
)

# Methods
result = evaluator.eval("2 + 2") # Evaluate expression
namespace = evaluator.exec("x = 10") # Execute code
results = evaluator.eval_many(["1+1", "2+2"]) # Batch evaluation
analysis = evaluator.analyze("import os") # Analyze only

Error Handling​

from ascend.wrappers.dynamic_code import (
safe_eval,
SafeEvalError, # Base exception
CodeTooLongError, # Code exceeds max length
DangerousCodeError, # Dangerous constructs detected by AST
GovernanceError, # Governance check failed
TimeoutError # Execution timeout
)

try:
result = safe_eval("__import__('os').system('rm -rf /')")
except DangerousCodeError as e:
print(f"Code blocked by AST analysis: {e}")
except GovernanceError as e:
print(f"Code denied by ASCEND: {e}")
except TimeoutError as e:
print(f"Execution timeout: {e}")

Configuration​

from ascend.wrappers.dynamic_code import configure

configure(
client=ascend_client, # AscendClient instance
fail_mode='closed', # 'closed' (default) or 'open'
allowed_builtins={"sum", "len"}, # Override default builtins
blocked_names={"custom_func"}, # Additional blocked names
max_code_length=10000, # Max code length
timeout_seconds=5 # Execution timeout
)

Environment Variables​

VariableDefaultDescription
ASCEND_EVAL_FAIL_MODEclosedFail mode when API unavailable
ASCEND_EVAL_MAX_LENGTH10000Maximum code length
ASCEND_EVAL_TIMEOUT5Execution timeout (seconds)

ASTAnalysisResult​

The analyze() method returns an ASTAnalysisResult:

analysis = evaluator.analyze("import os")

print(analysis.is_safe) # False (critical/high findings)
print(analysis.has_dangerous_constructs) # True
print(analysis.max_severity) # "critical"
print(analysis.reason) # Description of most severe finding
print(analysis.code_length) # Code length
print(len(analysis.findings)) # Number of findings

Example: Safe Calculator​

from ascend.wrappers.dynamic_code import SafeEvaluator

calculator = SafeEvaluator(
allowed_builtins={"abs", "round", "min", "max", "sum", "pow", "int", "float"},
timeout_seconds=1
)

# Safe math operations
calculator.eval("2 + 2") # 4
calculator.eval("pow(2, 10)") # 1024
calculator.eval("sum([1,2,3,4])") # 10
calculator.eval("round(3.14159, 2)") # 3.14

# With context
calculator.eval("price * (1 - discount)", {"price": 100, "discount": 0.1}) # 90.0

# Blocked - DangerousCodeError
calculator.eval("__import__('os')")
calculator.eval("open('/etc/passwd')")
calculator.eval("().__class__.__bases__[0].__subclasses__()")

Compliance​

  • CWE-94: Code Injection
  • CWE-95: Eval Injection
  • CWE-502: Deserialization of Untrusted Data
  • MITRE ATT&CK: T1059.006 (Python)
  • NIST 800-53: SI-10 (Information Input Validation)
  • OWASP: A03:2021 - Injection

Best Practices​

  1. Prefer safe_eval over eval - Always use the wrapper
  2. Limit allowed builtins - Only include what you need
  3. Set timeouts - Prevent infinite loops
  4. Configure ASCEND client - Get governance audit trail
  5. Use analyze() first - Check code before executing
  6. Monitor audit logs - Review blocked attempts