T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/create_angle_task.sh:42
- Finding
- Unescaped User Input Permits JSON Request Injection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/create_angle_task.sh:42-57` **Vulnerability Type**: Improper construction of JSON from untrusted input **Risk Level**: Medium ### Vulnerable Code ```bash # 获取参数 IMAGE_URL="$1" CAMERA_PROMPT="$2" WEB_APP_ID="${3:-43531}" # 验证摄像机提示词格式 if [[ ! "$CAMERA_PROMPT" =~ ^\<sks\>\ .+ ]]; then echo -e "${RED}❌ 错误: 摄像机提示词必须以 <sks> 开头${NC}" echo "💡 正确格式示例: <sks> left side view low-angle shot close-up" exit 1 fi # 构建请求数据 REQUEST_DATA=$(cat <<EOF { "web_app_id": ${WEB_APP_ID}, "suppress_preview_output": false, "input_values": { "41:LoadImage.image": "${IMAGE_URL}", "112:TextEncodeQwenImageEditPlus.prompt": "${CAMERA_PROMPT}\n" } } EOF ) ``` ### Technical Analysis The script directly interpolates three command-line arguments into a JSON document: - `IMAGE_URL` is inserted into a JSON string without JSON escaping. - `CAMERA_PROMPT` is inserted into a JSON string without JSON escaping. - `WEB_APP_ID` is inserted as raw JSON without numeric validation or an allowlist. The prompt validation only confirms that the value begins with `<sks> `. It does not restrict the remainder to one of the documented 96 prompts and does not prevent quotes, backslashes, newlines, or JSON syntax from appearing after the prefix. Consequently, a caller can terminate the intended JSON string or provide an arbitrary JSON expression through `WEB_APP_ID`. The modified payload is then transmitted using the legitimate `BIZYAIR_API_KEY` in the authorization header. This is JSON injection rather than shell command injection: shell metacharacters inside the variables are not reparsed as commands, but they can alter the API request body. ### Attack Path 1. The attacker gains the ability to influence arguments passed to `create_angle_task.sh`, such as through an agent-generated invocation or an application wrapper. 2. The attacker supplies a crafted image URL, prompt, or workflow ID containing JSON delimiters an ...[truncated 1040 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Construct the request with a real JSON serializer such as `jq`: ```bash if [[ ! "$WEB_APP_ID" =~ ^[0-9]+$ ]]; then echo "Invalid web_app_id" >&2 exit 1 fi case "$WEB_APP_ID" in 43531) ;; *) echo "Unsupported web_app_id" >&2 exit 1 ;; esac REQUEST_DATA="$( jq -n \ --argjson web_app_id "$WEB_APP_ID" \ --arg image_url "$IMAGE_URL" \ --arg prompt "${CAMERA_PROMPT}"$'\n' \ '{ web_app_id: $web_app_id, suppress_preview_output: false, input_values: { "41:LoadImage.image": $image_url, "112:TextEncodeQwenImageEditPlus.prompt": $prompt } }' )" ``` 2. Validate `CAMERA_PROMPT` against an exact allowlist of the 96 supported values rather than checking only its prefix. 3. Restrict `WEB_APP_ID` to the required workflow ID, or to a small explicit allowlist if multiple workflows are necessary. 4. Validate `IMAGE_URL` as an HTTPS URL and, where feasible, restrict its hostname to approved image-storage domains. 5. Reject control characters and enforce reasonable maximum lengths for all arguments. 6. Use `curl --fail-with-body` and verify that serialization succeeded before sending the authenticated request. ]]>
