T07 · Tool Hijacking and Spoofing
Error
- Location
- scripts/generate_sketch.py:17
- Finding
- Python Import Path Precedence Enables Local Package Hijacking<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_sketch.py`, lines 17–20 **Vulnerability Type**: Python module search-path hijacking **Risk Level**: High ### Vulnerable Code ```python # Ensure MechanicsSketches is importable sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "..")) from MechanicsSketches import * # noqa: E402 from MechanicsSketches.qt_renderer import render # noqa: E402 ``` ### Technical Analysis The script inserts a three-level ancestor of its own directory at index zero of `sys.path`. In the audited directory layout, this resolves to `/tmp`, which commonly permits unprivileged users to create files and directories. Because this path takes precedence over installed packages, Python may import a locally planted `MechanicsSketches` package instead of the legitimate dependency. Importing a Python package executes its initialization code, so a malicious `MechanicsSketches/__init__.py` or `MechanicsSketches/qt_renderer.py` can execute arbitrary Python code before the helper processes the input sketch. Exploitation requires an attacker to be able to create the spoofed package in the inserted ancestor directory before a victim runs the script. The issue is especially significant in shared temporary directories or automated environments where multiple users or jobs operate under different trust boundaries. ### Attack Path 1. An attacker determines that the helper script inserts `/tmp` or another attacker-writable ancestor at the beginning of `sys.path`. 2. The attacker creates a spoofed package, such as: - `/tmp/MechanicsSketches/__init__.py` - `/tmp/MechanicsSketches/qt_renderer.py` 3. The package files contain attacker-controlled Python code and optionally expose enough expected names to avoid an immediate import failure. 4. A victim invokes the documented command: ```bash python scripts/generate_sketch.py input.json output.pdf ``` 5. Python resolves `MechanicsSketches` from the att ...[truncated 719 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove the search-path modification and import the installed dependency normally: ```python from MechanicsSketches import ( create_sketch, add_beam, add_truss, add_pinned_support, add_roller_support, add_fixed_support, add_hinge, add_force, add_moment, add_dimension_arrow, add_dimension_thickness, add_coordinate_system, add_text, ) from MechanicsSketches.qt_renderer import render ``` 2. Install the dependency into an isolated virtual environment rather than manipulating `sys.path`. 3. If source-tree imports are required for development, calculate the exact expected repository directory and validate it before use. At minimum: - Resolve the path with `pathlib.Path.resolve()`. - Confirm that it is inside the trusted project root. - Reject world-writable or group-writable directories. - Never add a shared temporary directory to the front of `sys.path`. 4. Replace the wildcard import with explicit imports. This limits namespace manipulation and makes the expected dependency interface auditable. 5. Run the helper with least privilege and use isolated temporary directories with restrictive permissions in shared or automated environments. ]]>
