T09 · Insecure Skill Coding Practices
- Location
scripts/analyze.sh:362- Finding
Unescaped Attacker-Controlled Values in JSON Output
- Content
View full analysis
Vulnerability Details
File Location:
scripts/analyze.sh, lines 362–385
Vulnerability Type: Improper JSON encoding / output injection
Risk Level: MediumVulnerable Code
bash echo " \"workspace\": \"$WORKSPACE\"," echo " \"model\": \"$MODEL\"," echo " \"model_tier\": \"$MODEL_TIER\"," echo " \"input_price_per_mtok\": $INPUT_PRICE," echo " \"output_price_per_mtok\": $OUTPUT_PRICE," echo " \"turns_per_day\": $TURNS_PER_DAY," echo " \"workspace_tokens\": $total_ws_tokens," echo " \"skill_tokens\": $skill_total_tokens," echo " \"total_input_tokens_per_turn\": $total_input_tokens," echo " \"daily_cost\": $daily_total," echo " \"monthly_cost\": $monthly_total," echo " \"optimized_monthly\": $optimized_monthly," echo " \"savings_percent\": $pct_savings," echo " \"files\": [" for i in "${!file_names[@]}"; do comma="" [ "$i" -lt $((${#file_names[@]} - 1)) ] && comma="," echo " {\"name\": \"${file_names[$i]}\", \"tokens\": ${file_tokens[$i]}, \"monthly_cost\": ${file_monthly[$i]}}${comma}" done echo " ]," echo " \"recommendations\": [" for i in "${!rec_descriptions[@]}"; do comma="" [ "$i" -lt $((${#rec_descriptions[@]} - 1)) ] && comma="," # Escape quotes in description desc=$(echo "${rec_descriptions[$i]}" | sed 's/"/\\"/g') action=$(echo "${rec_actions[$i]}" | sed 's/"/\\"/g') echo " {\"rank\": $((i+1)), \"description\": \"$desc\", \"monthly_savings\": ${rec_savings[$i]}, \"action\": \"$action\"}${comma}" doneTechnical Analysis
The script constructs machine-readable JSON through string interpolation rather than a JSON encoder. Several values inserted into JSON strings can be influenced by untrusted workspace or configuration content:
WORKSPACEis supplied as a command-line argument.MODELis extracted from an OpenClaw configuration file or environment variable.file_namescontains filenames from the scanned workspace.- Recommendation descriptions can incorporate those filenames.
...[truncated 2098 chars]
- Remediation
View remediation
Remediation Suggestions
Use a mature JSON serializer instead of constructing JSON manually. For example, use
jqwith--argfor strings and--argjsonfor validated numeric values.If maintaining a dependency-free implementation is mandatory, implement and thoroughly test complete RFC 8259 escaping for:
- Double quotation marks.
- Backslashes.
- Newlines, carriage returns, tabs, and other control characters.
- Control bytes in the
U+0000throughU+001Frange.
Additional hardening measures should include:
- Validate
FORMATagainst an explicit allowlist such astextandjson. - Validate pricing and calculated values as numeric before emitting them as JSON numbers.
- Encode
WORKSPACE,MODEL, filenames, descriptions, and actions through the same centralized JSON-string function. - Add regression tests using paths, model values, and filenames containing quotes, backslashes, newlines, tabs, Unicode characters, and attempted JSON property injection.
- Parse generated output with a strict JSON parser in tests to guarantee that every supported input produces exactly one valid JSON document.
