T09 · Insecure Skill Coding Practices
- Location
interfaces/critic_engine.py:356- Finding
Unsandboxed Execution of Evaluated Python Skills
- Content
View full analysis
Vulnerability Details
File Location:
interfaces/critic_engine.py:356-379
Vulnerability Type: Arbitrary code execution through dynamic module loading
Risk Level: HighVulnerable Code
python def _load_skill(self): """加载 Skill 模块""" # 尝试加载 Python 文件 py_files = list(self.skill_path.glob("*.py")) if self.skill_path.is_dir() else [self.skill_path] # 优先查找 main.py 或 evaluate.py priority_files = ["main.py", "evaluate.py", "executor.py"] target_file = None for pf in priority_files: candidate = self.skill_path / pf if self.skill_path.is_dir() else self.skill_path if candidate.exists() and candidate.name == pf: target_file = candidate break if not target_file and py_files: target_file = py_files[0] if not target_file: raise ValueError(f"No Python files found in {self.skill_path}") # 加载模块 spec = importlib.util.spec_from_file_location("skill_module", target_file) if spec and spec.loader: self.skill_module = importlib.util.module_from_spec(spec) sys.modules["skill_module"] = self.skill_module spec.loader.exec_module(self.skill_module)Technical Analysis
RealSkillEvaluatordynamically imports a Python file selected from the caller-suppliedskill_path. Callingspec.loader.exec_module()executes all module-level code immediately, before the implementation verifies that the module exposes an expectedevaluate,execute,run, ormainfunction.The evaluated module runs in the same process and under the same operating-system identity as the critic engine. No sandbox, subprocess boundary, filesystem restriction, network restriction, resource limit, or environment-variable filtering is applied. Consequently, evaluating an untrusted skill is equivalent to granting that skill arbitrary Python code execution.
This capability exceeds the minimum ...[truncated 1107 chars]
- Remediation
View remediation
Remediation Suggestions
- Do not import reviewed or candidate-controlled Python modules into the critic process.
- Execute dynamic skills in a disposable sandbox or isolated worker with:
- No inherited secrets or API credentials.
- Network access disabled by default.
- A read-only, allowlisted filesystem.
- A dedicated unprivileged operating-system identity.
- CPU, memory, process-count, and execution-time limits.
- A strict structured input and output protocol.
- Resolve and validate the candidate path against an explicitly approved skill root.
- Reject symlinks, special files, and paths escaping the approved root.
- Require an explicit manifest that identifies the entry point instead of selecting the first Python file.
- Perform static validation before execution, while recognizing that static validation alone is not an adequate sandbox.
- Remove the global
sys.modules["skill_module"]mutation or assign a unique isolated module name if trusted in-process loading remains necessary.
