T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/get-note-detail.sh:4
- Finding
- Unsafe JSON Construction in the Bash Note-Detail Request<![CDATA[ ## Vulnerability Details **File Location**: `scripts/get-note-detail.sh:4-14` **Vulnerability Type**: JSON injection through unescaped user-controlled input **Risk Level**: Medium ### Vulnerable Code ```bash source "$(dirname "$0")/_common.sh" GUID="$1" if [ -z "$GUID" ]; then echo "用法: $0 <笔记GUID>" exit 1 fi curl -s -X POST \ "https://app.yinxiang.com/third/ai-chat-note/grpc-api/search/getNoteDetail" \ -H "Content-Type: application/json" \ -H "auth: $TOKEN" \ -d "{\"guid\":\"$GUID\",\"source\":\"skill\",\"resultSpec\":{\"includeContent\":true,\"includeResources\":false,\"includeTags\":true,\"includeResourceContent\":false}}" ``` ### Technical Analysis The script inserts the first command-line argument directly into a JSON string without applying JSON escaping or validating the expected GUID format. Shell quoting prevents ordinary shell command substitution inside the already-expanded variable, so this is not a local shell-command injection vulnerability. However, characters such as quotes and backslashes can terminate or alter the JSON string. For example, a crafted value could inject additional JSON properties or create duplicate properties. Whether an altered request is accepted, and which duplicate value takes precedence, depends on the remote service's JSON parser and request validation. The project already uses `python3` with `json.dumps` in other Bash scripts, demonstrating that safe serialization is available but is not used here. ### Attack Path 1. An attacker persuades a user or agent to process a crafted value as a note GUID. 2. The agent invokes `get-note-detail.sh` with the crafted value as its first argument. 3. The script places that value directly inside the JSON request body. 4. Quotes or JSON delimiters in the value alter or invalidate the request structure. 5. The authenticated request is sent to the Yinxiang note-detail endpoint using the victim's token. 6. If the server accepts the modified structure, unintend ...[truncated 640 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Construct the request as a native object and serialize it with a JSON encoder: ```bash BODY=$(python3 - "$GUID" <<'PY' import json import sys body = { "guid": sys.argv[1], "source": "skill", "resultSpec": { "includeContent": True, "includeResources": False, "includeTags": True, "includeResourceContent": False, }, } print(json.dumps(body, ensure_ascii=False)) PY ) curl -s -X POST \ "https://app.yinxiang.com/third/ai-chat-note/grpc-api/search/getNoteDetail" \ -H "Content-Type: application/json" \ -H "auth: $TOKEN" \ -d "$BODY" ``` Additionally: - Validate that the value matches the documented GUID format before sending it. - Reject control characters and unexpected input lengths. - Add regression tests containing quotes, backslashes, newlines, and JSON delimiters. - Apply the same serialization pattern consistently to every request body. ]]>
