T09 · Insecure Skill Coding Practices
Error
- Location
- daemon.py:22
- Finding
- Arbitrary Command Injection Through Market-Controlled Notification Content<![CDATA[ ## Vulnerability Details **File Location**: `daemon.py`, lines 22-23 **Vulnerability Type**: OS command injection **Risk Level**: High ### Vulnerable Code ```python safe_msg = msg.replace('"', '\\"') cmd = f'''osascript -e 'display notification "{safe_msg}" with title "{title}" sound name "Glass"'''' os.system(cmd) ``` The notification content originates from market data retrieved without transport authentication: ```python url = f"http://qt.gtimg.cn/q={codes}" resp = requests.get(url, timeout=1.0) lines = resp.text.strip().split(';') ``` ### Technical Analysis The application constructs a shell command by interpolating `safe_msg` and `title` into a string and then executes it through `os.system()`. Because `os.system()` invokes a command shell, shell metacharacters in interpolated values are interpreted rather than treated strictly as notification data. The attempted sanitization only escapes double quotation marks: ```python safe_msg = msg.replace('"', '\\"') ``` This does not protect the command's outer single-quoted AppleScript expression. An instrument name containing a single quote can terminate that shell-quoted expression. Subsequent shell syntax can then introduce an additional command. The message includes remotely supplied instrument names parsed from a plaintext HTTP response. Consequently, an attacker capable of modifying that response can potentially control part of `msg`. Exploitation also requires the forged response to satisfy one of the alert conditions so that `notify_mac()` is called. ### Attack Path 1. The daemon requests market data from `http://qt.gtimg.cn` over plaintext HTTP. 2. A network-positioned attacker intercepts or modifies the response. 3. The attacker supplies a syntactically valid response containing: - An instrument name with a single quote followed by shell command syntax. - Numeric values that satisfy a bond-linkage or ETF-premium alert condition. 4. The manipulated instrument name is incorporated ...[truncated 837 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove the shell from the execution path. Invoke AppleScript with an argument list: ```python import subprocess subprocess.run( ["osascript", "-e", script], shell=False, check=True, ) ``` 2. Do not assume that `shell=False` alone makes dynamically generated AppleScript safe. Encode or escape all values according to AppleScript string-literal rules, including backslashes, quotation marks, and control characters. A safer design is to pass data as separate `osascript` arguments and read it from `argv` in an AppleScript handler. 3. Strictly validate market-data fields before using them: - Allow only expected stock-code syntax. - Reject malformed numeric fields. - Apply a conservative allowlist to instrument names or remove control characters and shell-relevant punctuation. - Enforce maximum field lengths. 4. Use HTTPS with certificate verification if the provider offers an authenticated HTTPS endpoint. If not, use a trusted market-data source that provides transport authentication. 5. Treat all external market data as untrusted, even after transport security is added. 6. Run the monitor as a dedicated, unprivileged user with minimal filesystem and credential access. 7. Add tests containing single quotes, semicolons, command substitutions, newlines, and malformed AppleScript input to verify that none can cause additional process execution. ]]>
