T09 · Insecure Skill Coding Practices
- Location
SKILL.md:91- Finding
Python Code Injection Through a DerivedData Directory Name in Latest Build Summary
- Content
View full analysis
/dev/null | python3 -c " import json, sys from datetime import datetime, timezone, timedelta data = json.load(sys.stdin) EPOCH = datetime(2001, 1, 1, tzinfo=timezone.utc) name = '$NAME' latest = None ``` ### Technical Analysis The DerivedData directory basename is assigned to the shell variable `NAME` and then directly interpolated into the source passed to `python3 -c`: ```python name = '$NAME' ``` Shell quoting does not escape the value for use inside a Python string literal. If the directory name contains a single quote followed by valid Python statements, the value can terminate the intended string literal and inject additional Python code. The loop processes every matching `*-*` directory and only requires the directory to contain `Logs/Build/LogStoreManifest.plist`. An attacker with write access to the current user's DerivedData directory can therefore create a specially named directory and a valid manifest that passes these checks. For example, a basename shaped like the following can become executable Python after the trailing suffix is removed by `sed`: ```text x';__import__("os").system("id");#-a ``` The `sed 's/-[a-z]*$//'` operation removes `-a`, leaving attacker-controlled Python syntax. A valid plist is also needed because `json.load(sys.stdin)` executes before the vulnerable assignment. ### Attack Path 1. An attacker obtains the ability to create files and directories under the victim's `~/Library/Developer/Xcode/DerivedData/` directory. 2. The attacker ...[truncated 1214 chars]- Remediation
View remediation
/dev/null | python3 -c ' import json import os import sys from datetime import datetime, timezone, timedelta data = json.load(sys.stdin) EPOCH = datetime(2001, 1, 1, tzinfo=timezone.utc) name = os.environ["NAME"] latest = None ' ``` Alternatively, use a standalone Python script and pass `NAME` through `sys.argv`. Python source should remain constant regardless of directory names. Additional hardening should include: - Treating every filename and plist field as untrusted input. - Validating manifest structure and expected field types before processing. - Avoiding broad permissions such as Full Disk Access unless a specific operation demonstrably requires them. - Adding tests with directory names containing quotes, semicolons, newlines, backslashes, and Unicode characters. ]]>
