T09 · Insecure Skill Coding Practices
Warning
- Location
- lib/check-single.sh:17
- Finding
- Insufficient URL Validation Enables Blind Server-Side Request Forgery## Vulnerability Details **File Location**: `testflight-monitor.sh:81-86`, `lib/check-single.sh:17-31`, and `lib/check-batch.sh:23-42` **Vulnerability Type**: Blind server-side request forgery caused by unrestricted URL fetching **Risk Level**: Medium ### Vulnerable Code `testflight-monitor.sh:81-86`: ```bash add) [[ $# -lt 2 ]] && { echo "Error: add requires a URL"; exit 1; } URL="$2" jq --arg url "$URL" '.links += [$url] | .links |= unique' "$SCRIPT_DIR/config/batch-config.json" > "$SCRIPT_DIR/config/batch-config.json.tmp" mv "$SCRIPT_DIR/config/batch-config.json.tmp" "$SCRIPT_DIR/config/batch-config.json" echo "✓ Added: $URL" ``` `lib/check-single.sh:17-31`: ```bash # Extract code from URL CODE=$(echo "$URL" | grep -oE '[A-Za-z0-9]{8}$' || true) if [[ -z "$CODE" ]]; then echo "Error: Invalid TestFlight URL: $URL" >&2 exit 1 fi # Look up app name APP_NAME=$("$LOOKUP" "$CODE" 2>/dev/null || echo "Beta $CODE") echo "Checking $URL..." # Fetch the page HTML=$(curl -sSL -H "User-Agent: Mozilla/5.0" "$URL" 2>&1 || true) ``` `lib/check-batch.sh:23-42`: ```bash # Read tracked links from config TRACKED_LINKS=$(jq -r '.links[]' "$CONFIG_FILE" 2>/dev/null || echo "") if [[ -z "$TRACKED_LINKS" ]]; then echo "No TestFlight URLs configured for monitoring." echo "Add URLs with: testflight-monitor.sh add <url>" exit 0 fi CHANGES=() while IFS= read -r URL; do # Extract code from URL CODE=$(echo "$URL" | grep -oE '[A-Za-z0-9]{8}$') # Look up app name APP_NAME=$("$LOOKUP" "$CODE" 2>/dev/null || echo "$CODE") # Check current status (suppress output) if bash "$CHECKER" "$URL" 2>&1 | grep -q "AVAILABLE"; then ``` ### Technical Analysis The checker treats a URL as valid whenever its final eight characters are alphanumeric. It does not require: - The `https` scheme - The exact `testflight.apple.com` host - The expected `/join/` path - The absence of embedded credentials or nonstandard ports - A public destination address - A saf ...[truncated 2500 chars]
- Remediation
- ## Remediation Suggestions 1. Validate URLs before storing them and again immediately before every network request. 2. Require the exact expected structure: - Scheme: `https` - Host: `testflight.apple.com` - Port: default HTTPS port only - Path: exactly `/join/[A-Za-z0-9]{8}` - No username, password, fragment, or unexpected query parameters 3. Use a proper URL parser rather than a suffix-only regular expression. 4. Disable redirects with `--max-redirs 0`. If redirects are operationally required, validate every redirect target against the same strict origin policy. 5. Reject destinations resolving to loopback, private, link-local, multicast, reserved, and cloud metadata address ranges. Revalidate after DNS resolution to reduce DNS rebinding risk. 6. Add network safety limits such as: ```bash curl \ --fail \ --silent \ --show-error \ --connect-timeout 5 \ --max-time 15 \ --max-redirs 0 \ --proto '=https' \ --max-filesize 1048576 \ -H "User-Agent: Mozilla/5.0" \ "$URL" ``` 7. Reject invalid entries in `add` rather than allowing unsafe values to enter persistent configuration. 8. Treat network failures and unknown responses as `unknown`, not `full`, so that request failures do not corrupt monitoring state. 9. Consider enforcing outbound network policy at the runtime or container layer so the Skill can reach only the required Apple hostname.
