File: maithili_dsl/cli.py (_validate_imports)
The pre-exec import check is line-prefix-based (stripped.startswith('import ')), so statements not at the start of a line are missed:
x = 1; import os # passes _validate_imports (verified)
Runtime is still guarded by the __import__ wrapper, so this is not a sandbox escape — only whitelisted modules load either way — but it silently defeats the documented "raw Python imports are rejected before execution" layer, and prefix matching will also miss conditional/indented imports.
Fix: parse with ast.parse() and walk ast.Import / ast.ImportFrom nodes instead of scanning lines. Bonus: this also gives precise line numbers for error messages, and a clean SyntaxError path for malformed code before exec.
Tests: semicolon repro above, indented import inside यदि, from os import path variants — all in tests/test_security.py (per CONTRIBUTING.md this touches the sandbox, so a Security Considerations section is required in the PR).
File:
maithili_dsl/cli.py(_validate_imports)The pre-exec import check is line-prefix-based (
stripped.startswith('import ')), so statements not at the start of a line are missed:Runtime is still guarded by the
__import__wrapper, so this is not a sandbox escape — only whitelisted modules load either way — but it silently defeats the documented "raw Python imports are rejected before execution" layer, and prefix matching will also miss conditional/indented imports.Fix: parse with
ast.parse()and walkast.Import/ast.ImportFromnodes instead of scanning lines. Bonus: this also gives precise line numbers for error messages, and a cleanSyntaxErrorpath for malformed code beforeexec.Tests: semicolon repro above, indented import inside
यदि,from os import pathvariants — all intests/test_security.py(per CONTRIBUTING.md this touches the sandbox, so a Security Considerations section is required in the PR).