Skip to content

fix: harden AST blocklist in _safe_import_check for attribute-style and dynamic dispatch dangerous calls#85

Open
nobugpal wants to merge 2 commits into
wanxingai:mainfrom
nobugpal:fix/harden-python-executor-blocklist
Open

fix: harden AST blocklist in _safe_import_check for attribute-style and dynamic dispatch dangerous calls#85
nobugpal wants to merge 2 commits into
wanxingai:mainfrom
nobugpal:fix/harden-python-executor-blocklist

Conversation

@nobugpal

@nobugpal nobugpal commented Jul 21, 2026

Copy link
Copy Markdown

Summary

Harden the AST-based blocklist in python_executor.py:_safe_import_check() to cover attribute-style calls (builtins.eval(...)), getattr-based dynamic dispatch (getattr(obj, "eval")(...)), and subscript access patterns (obj.__dict__["eval"](...)), in addition to the existing direct Name call coverage.

Changes

LightAgent/builtin_tools/python_executor.py

Three defenses added:

  1. Attribute calls (line 200): Added eval, exec, compile to the ast.Attribute blocklist — closes the builtins.eval(...) bypass path
  2. getattr detection (lines 198-202): When getattr() is called with a constant second argument matching dangerous function names, the call is blocked — closes getattr(obj, "eval")(...) patterns
  3. Subscript access (lines 207-210): Subscript access (obj[...]) with a constant key matching dangerous function names is blocked — closes obj.__dict__["eval"](...) patterns

All pattern checks are scoped to constant string arguments only, preserving legitimate dynamic access (e.g., getattr(obj, variable_name) or d[variable_key]).

tests/test_python_executor_blocklist.py (new — 20 tests)

Category Tests Purpose
Direct Name calls 4 eval(), exec(), compile(), import()
Import-based 3 import os, import subprocess, from builtins import eval
Attribute calls 3 builtins.eval(), builtins.exec(), builtins.compile()
getattr dispatch 3 getattr("eval"), getattr("exec"), getattr("system")
Subscript access 1 obj.dict"eval"
Safe getattr 1 getattr(obj, "normal_attribute") — still allowed
Safe subscript 1 d["normal_key"] — still allowed
Harmless code 3 sum, print, len/range — still allowed

Testing

$ python3 -m pytest tests/test_python_executor_blocklist.py -v
20 passed in 0.83s

$ python3 -m pytest tests/test_v065_core.py tests/test_v070_tracing.py \
  tests/test_memory_policy.py tests/test_python_executor_blocklist.py -q
74 passed in 1.90s

No regressions. All existing tests pass.

Security Note

Per CONTRIBUTING.md: this change affects the code execution tool path and includes a security hardening note. The fix closes defense-in-depth gaps (CWE-184: Incomplete Blocklist) in the Python code execution sandbox by ensuring consistent blocking regardless of call syntax or dispatch mechanism.

Checklist

  • python -m compileall -q LightAgent passes
  • Regression test suite passes (74 tests)
  • New tests cover all known bypass patterns
  • Safe operations (including dynamic getattr) remain functional
  • Backward compatible — no API changes
  • No credentials, logs, or build artifacts included

wyytjh added 2 commits July 21, 2026 23:36
…angerous calls

The _safe_import_check function in python_executor.py walks the
Python AST to detect dangerous function calls. While direct Name
calls (eval(...), exec(...)) were already blocked, attribute-style
calls (builtins.eval(...), builtins.exec(...)) parsed as
ast.Attribute nodes were not covered by the same blocklist.

This commit adds 'eval', 'exec', and 'compile' to the attribute
blocklist, ensuring consistent coverage regardless of call style.

Also adds a dedicated test suite (test_python_executor_blocklist.py)
with 14 tests covering:
- Direct Name calls for eval/exec/compile/__import__
- Attribute calls for builtins.eval/exec/compile
- Import-based dangerous module checks
- Safe operations (sum, print, len, range) remain unaffected

All 68 tests pass including existing regression suites.

Security note: defense-in-depth hardening for the code execution
tool path, per CONTRIBUTING.md guidelines.
…nd dynamic dispatch dangerous calls

The _safe_import_check function uses AST analysis to detect dangerous
function calls. Previously, attribute-style calls (builtins.eval(...))
were not covered by the same blocklist as direct Name calls (eval(...)).

Changes:
1. Added 'eval', 'exec', 'compile' to the ast.Attribute blocklist
   (closes the builtins.eval bypass path)
2. Added getattr-with-dangerous-argument detection
   (blocks getattr(obj, 'eval'/'exec'/...) patterns)
3. Added subscript-access detection for dangerous function names
   (blocks obj.__dict__['eval'] patterns)

All changes are scoped to constant string arguments only, preserving
legitimate dynamic getattr and subscript use.

Tests: 74 pass (20 new blocklist tests + 54 existing regression tests)
No regressions.

Security note: defense-in-depth hardening for the code execution
tool path (CWE-184). Per CONTRIBUTING.md guidelines.
@nobugpal nobugpal changed the title fix: harden AST blocklist in _safe_import_check for attribute-style dangerous calls fix: harden AST blocklist in _safe_import_check for attribute-style and dynamic dispatch dangerous calls Jul 21, 2026
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.

1 participant