T07 · Tool Hijacking and Spoofing
Error
- Location
- scripts/run.py:263
- Finding
- Unauthenticated External Preprocessor Module Execution<![CDATA[ ## Vulnerability Details **File Location**: `scripts/run.py`, lines 263-270 **Vulnerability Type**: Dynamic execution of an unverified module outside the skill package **Risk Level**: High ### Vulnerable Code ```python _shared_dir = Path(__file__).resolve().parent.parents[3] / "_shared" / "doc-preprocess" / "scripts" if not _shared_dir.exists(): print(f"ERROR: 无法读取输入文件,本地预处理失败且 _shared/doc-preprocess 不可用。原因:{exc}", file=sys.stderr) return 1 import importlib.util as _iu _spec = _iu.spec_from_file_location("_shared_preprocess", _shared_dir / "preprocess.py") _sp = _iu.module_from_spec(_spec) _spec.loader.exec_module(_sp) ``` ### Technical Analysis When local preprocessing raises `PreprocessError`, the application constructs a path outside the skill package and dynamically loads `preprocess.py` from that location. It verifies only that the shared directory exists; it does not verify the module's cryptographic hash, ownership, permissions, provenance, or expected contents. Calling `exec_module()` executes all top-level Python statements in the selected file. Consequently, if another user, process, package, or compromised deployment component can create or replace the external `preprocess.py`, that party can cause arbitrary Python code to run when the fallback path is reached. The exact resolved shared directory depends on the installation layout. Exploitation therefore requires the resolved location, or one of its controlling parent directories, to be writable or otherwise replaceable by the attacker. ### Attack Path 1. The attacker determines the external path generated from `Path(__file__).resolve().parent.parents[3]`. 2. The attacker obtains write access to the resulting `_shared/doc-preprocess/scripts` directory or can replace its `preprocess.py`. 3. The attacker places a malicious `preprocess.py` at that location. Malicious top-level code is sufficient; no preprocessor function needs to be called. 4. The attacker or a victim invokes th ...[truncated 1101 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove the external dynamic-import fallback and package all required preprocessing code inside the reviewed skill. 2. If a shared component is required, import it as a properly installed, version-pinned package from a trusted environment rather than loading a file from a computed path. 3. Pin and verify a cryptographic digest or signed manifest before loading shared code. 4. Validate the resolved path with `Path.resolve()` and require it to reside beneath an explicitly configured, administrator-controlled directory. 5. Reject symbolic links and verify that the file and every controlling parent directory are owned by a trusted account and are not group- or world-writable. 6. Apply least privilege to the skill process and isolate it with filesystem and network sandboxing so compromise of a preprocessor has limited impact. 7. Fail closed when preprocessing is unavailable instead of automatically executing an unverified alternative implementation. ]]>
