T09 · Insecure Skill Coding Practices
Warning
- Location
- clup.sh:139
- Finding
- Unescaped User Input Allows JSON Payload Injection<![CDATA[ ## Vulnerability Details **File Location**: `clup.sh`, lines 139-158 **Vulnerability Type**: Improper JSON construction and injection **Risk Level**: Medium ### Vulnerable Code ```bash # Build tags array for JSON # Convert comma-separated string to JSON array: "tag1,tag2" -> ["tag1","tag2"] if [[ -n "$TAGS" ]]; then IFS=',' read -ra TAG_ARRAY <<< "$TAGS" TAGS_JSON=$(printf ',"%s"' "${TAG_ARRAY[@]}") TAGS_JSON="[${TAGS_JSON:1}]" # Remove leading comma and wrap in brackets else TAGS_JSON="[]" fi # Build JSON payload JSON_PAYLOAD=$(cat <<EOF { "name": "$TITLE", "description": "$DESCRIPTION", "status": "$STATUS", "tags": $TAGS_JSON } EOF ) ``` ### Technical Analysis The script constructs JSON through direct shell-string interpolation. The user-controlled `TITLE`, `DESCRIPTION`, `STATUS`, and `TAGS` values are inserted without JSON escaping or serialization. Characters such as double quotes, backslashes, newlines, and control characters can therefore produce malformed JSON. A deliberately crafted value may also terminate its original JSON string and introduce additional properties. Tag values are similarly enclosed in quotes using `printf` without escaping their contents. This issue is JSON injection rather than shell command injection: shell syntax embedded inside these variables is not automatically evaluated as a new shell command. The affected security boundary is the authenticated ClickUp API request. ### Attack Path 1. An attacker supplies a crafted ticket title, description, status, or tag value containing JSON syntax. 2. An AI agent or user passes that value to `clup.sh`. 3. The script interpolates the value directly into `JSON_PAYLOAD`. 4. The crafted input terminates or modifies the intended JSON structure. 5. If the resulting payload is valid and the ClickUp API accepts the injected fields, the API processes unintended task attributes using the configured `CLICKUP_API_KEY`. 6. Otherwise, the malformed payload c ...[truncated 543 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Construct the request with a JSON-aware serializer instead of shell interpolation. For example, use `jq` with `--arg` and `--argjson` so all string values are escaped correctly: ```bash IFS=',' read -ra TAG_ARRAY <<< "$TAGS" TAGS_JSON=$(printf '%s\n' "${TAG_ARRAY[@]}" | jq -R . | jq -s .) JSON_PAYLOAD=$( jq -n \ --arg name "$TITLE" \ --arg description "$DESCRIPTION" \ --arg status "$STATUS" \ --argjson tags "$TAGS_JSON" \ '{ name: $name, description: $description, status: $status, tags: $tags }' ) if [[ -n "$PRIORITY" ]]; then JSON_PAYLOAD=$( jq --argjson priority "$PRIORITY" \ '. + {priority: $priority}' <<< "$JSON_PAYLOAD" ) fi ``` Additional hardening measures: - Validate the allowed length and character set of status and tag values. - Reject control characters where they are not required. - Validate the final payload with a JSON parser before sending it. - Avoid using `sed` to modify serialized JSON. - Add tests covering quotes, backslashes, newlines, Unicode, empty tags, and attempted property injection. ]]>
