T09 · Insecure Skill Coding Practices
- Location
SKILL.md:14- Finding
User-Controlled Prompt Can Enable Shell Command Injection
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md:14-34
Additional Location:references/api.md:60-79
Vulnerability Type: Shell command injection through unsafe interpolation into a single-quotedcurlrequest body
Risk Level: HighVulnerable Code Snippet
bash curl -X POST 'https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation' \ -H 'Content-Type: application/json' \ -H "Authorization: Bearer $DASHSCOPE_API_KEY" \ -d '{ "model": "qwen-image-2.0-pro", "input": { "messages": [{ "role": "user", "content": [{"text": "你的提示词"}] }] }, "parameters": { "negative_prompt": "低分辨率,低画质,肢体畸形,手指畸形", "prompt_extend": true, "watermark": false, "size": "2048*2048" } }'The documented execution process instructs the agent to construct this JSON request from the user's prompt and execute it using
curl:text 1. Check API Key 2. Construct the request using the user's prompt and parameters 3. Call the API using curl 4. Parse the response 5. Return the image URLTechnical Analysis
The complete JSON request body is enclosed in a shell single-quoted string passed to
curlthrough-d. If an implementation directly replaces the prompt placeholder with user-controlled text, a single quote in that text terminates the shell string.The attacker can then introduce shell separators such as
;and append an arbitrary command. JSON escaping alone does not prevent this vulnerability because JSON escaping and shell escaping are different security boundaries. A prompt may be valid or safely escaped for JSON while remaining unsafe when concatenated into a shell command.The same unsafe construction pattern appears in both the primary skill instructions and the detailed API reference. No requirement is provided to use a JSON serializer, avoid shell interpolation, o ...[truncated 1957 chars]
- Remediation
View remediation
Remediation Suggestions
- Do not concatenate or substitute user-controlled prompts into shell command strings.
- Prefer a structured HTTP client that accepts headers and a serialized object separately from command execution.
- If
curlmust be used, serialize the payload to a file or standard input with a trusted JSON serializer and invokecurlusing fixed arguments. - For shell-based implementations, use
jqwith bound arguments:bash payload="$(jq -n --arg prompt "$USER_PROMPT" '{ model: "qwen-image-2.0-pro", input: { messages: [{ role: "user", content: [{text: $prompt}] }] }, parameters: { prompt_extend: true, watermark: false, size: "2048*2048" } }')" curl --fail-with-body \ --request POST \ 'https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation' \ --header 'Content-Type: application/json' \ --header "Authorization: Bearer ${DASHSCOPE_API_KEY}" \ --data-binary "$payload" - Pass command arguments as an argument array when invoking a subprocess; never enable a shell for this operation.
- Validate documented limits, including prompt length, model names, output dimensions, image count, and seed range. Validation should supplement—not replace—safe argument handling.
- Update both
SKILL.mdandreferences/api.mdso every executable example demonstrates safe handling of untrusted prompts. - Run the skill under a least-privileged account, restrict outbound network access where practical, and ensure API credentials have minimal permissions and usage limits.
