T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/search_cn.sh:4
- Finding
- Unvalidated Result-Count Argument Enables Arbitrary Local File Reads<![CDATA[ ## Vulnerability Details **File Location**: `scripts/search_cn.sh`, lines 4-10 **Vulnerability Type**: Shell argument injection caused by unquoted expansion and missing input validation **Risk Level**: Medium ### Vulnerable Code ```bash QUERY="$1" NUM="${2:-10}" BAIDU_API="https://www.baidu.com/s?wd=${QUERY}&rn=${NUM}" curl -s "${BAIDU_API}" -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" | grep -oP '<h3 class="news-title.*?">.*?<a href="(.*?)".*?>(.*?)</a>.*?</h3>' | head -${NUM} ``` ### Technical Analysis The second positional argument is assigned directly to `NUM` without verifying that it is a positive integer: ```bash NUM="${2:-10}" ``` It is subsequently expanded without quotation marks when passed to `head`: ```bash head -${NUM} ``` Bash performs word splitting on this unquoted expansion. A single attacker-controlled argument containing spaces can consequently become multiple arguments to `head`. In addition to supplying the intended line-count option, an attacker can inject a local file path as an input operand. For example, if the second script argument is supplied as the single string `1 /etc/passwd`, the resulting command is functionally equivalent to: ```bash head -1 /etc/passwd ``` The preceding `curl` or `grep` operation does not prevent exploitation. Even if the malformed result-count value causes the network request to fail, `head` can still open the injected file operand directly. This is argument injection rather than shell command substitution: shell metacharacters embedded in `NUM` are not reparsed as shell syntax. Nevertheless, the ability to inject operands into `head` creates a confirmed local-file disclosure primitive. ### Attack Path 1. An attacker obtains the ability to influence the second argument passed to `scripts/search_cn.sh`, directly or through an Agent-generated invocation. 2. The attacker supplies a value containing a valid `head` count followed by a local file path, suc ...[truncated 1075 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Require `NUM` to be a bounded positive integer before using it: ```bash QUERY="${1:-}" NUM="${2:-10}" if [[ ! "$NUM" =~ ^[1-9][0-9]*$ ]] || (( NUM > 100 )); then printf '%s\n' "NUM must be an integer from 1 to 100." >&2 exit 2 fi ``` Use the explicit `-n` option and quote the validated value: ```bash head -n "$NUM" ``` Construct the request using `curl` query-parameter encoding rather than interpolating user input directly into the URL: ```bash curl -sS --get \ --data-urlencode "wd=$QUERY" \ --data-urlencode "rn=$NUM" \ "https://www.baidu.com/s" \ -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" ``` The corrected pipeline should follow this pattern: ```bash curl -sS --get \ --data-urlencode "wd=$QUERY" \ --data-urlencode "rn=$NUM" \ "https://www.baidu.com/s" \ -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" | grep -oP '<h3 class="news-title.*?">.*?<a href="(.*?)".*?>(.*?)</a>.*?</h3>' | head -n "$NUM" ``` Additional hardening should include enabling strict shell behavior with `set -euo pipefail`, returning a nonzero status when the search pipeline fails, and testing the script with spaces, option-like values, negative numbers, oversized numbers, and file paths as the second argument. ]]>
