T09 · Insecure Skill Coding Practices
- Location
generate_images.py:64- Finding
Shell Command Injection Through Unvalidated Credentials and API Response Values
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is mostly a Xiaohongshu content generator, but its image helper uses unsafe shell commands, reads a shell profile for credentials, can make many paid API calls, and writes to hard-coded local paths.
Review carefully before installing. Only use this after replacing shell-based curl/cp calls with safe Python APIs, removing ~/.zshrc credential parsing, enforcing explicit confirmation and job limits for paid API calls, and changing output paths to a user-approved project-local directory.
generate_images.py:64Shell Command Injection Through Unvalidated Credentials and API Response Values
generate_images.py:94Unbounded and Excessive Billable API Operations on Script Invocation
generate_images.py:102Hard-Coded Absolute Output Paths Permit Writes Outside the Project Boundary
There is a material mismatch between the stated purpose and the behavior described by analysis: the skill is presented as a full Xiaohongshu creation workflow, but the behavior includes undeclared local environment access, fixed local output handling, and failure to implement several promised steps. Misrepresentation is dangerous because users may authorize execution expecting only content creation, while the skill may access secrets or modify the local system in ways that were not transparently disclosed.
This is the strongest concrete issue in the file: a tool capable of arbitrary shell execution is fed a command string assembled from prompt content and credentials. In the context of a content-creation skill, prompts may eventually be user-influenced, making this an especially dangerous path to local command execution.
}}
}}'
'''
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
return result.stdout
def get_task_status(task_id):
A shell-capable tool is invoked with a command string containing a remote task identifier and credentials. Even though the endpoint is fixed, remote-controlled task_id content could abuse the shell boundary, turning a status check into a command execution sink.
cmd = f'''curl -s "https://dashscope.aliyuncs.com/api/v1/tasks/{task_id}" \\
-H "Authorization: Bearer {API_KEY}"
'''
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
return result.stdout
def download_image(url, output_path):
The download step combines remote URL data with shell execution, creating a high-risk tool-parameter abuse path. If the upstream service or response is tampered with, this can execute arbitrary commands or write attacker-chosen content to local files.
def download_image(url, output_path):
cmd = f'curl -s "{url}" -o "{output_path}"'
subprocess.run(cmd, shell=True)
print("=" * 60)
print("开始生成穿搭图片...")
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
page0 = f"{dir_path}/page_0.png"
cover = f"{dir_path}/cover.png"
if os.path.exists(page0) and not os.path.exists(cover):
subprocess.run(f'cp "{page0}" "{cover}"', shell=True)
print(f" ✓ {cover}")
print("\n✅ 全部完成!")
The manifest frames this as a Xiaohongshu creator and explicitly says it is not for other platforms such as Douyin/Weibo. However, the README's feature list says the skill auto-collects trends from Weibo, Douyin, Vogue, Pinterest, and Instagram, expanding behavior beyond the manifest's stated platform scope.
The skill documents capabilities that require shell execution, file reads, and environment variable access, but it does not declare any tool scope or permissions. This weakens least-privilege controls and can cause the agent to access local files or secrets more broadly than users would reasonably expect.
The skill is written to operate entirely in Chinese and the invocation/output examples assume Chinese-language use, but there is no statement that this is optional or limited to a justified region-specific deployment. Under the policy, forcing a specific language without opt-in is a natural-language policy concern.
The activation phrases are broad enough that normal conversation such as '创作小红书' or '收集素材' could trigger a workflow with network access, local file writes, and external API calls. Ambiguous triggering is risky because it can cause unintended execution of side-effectful actions without sufficiently explicit user consent.
The manifest says the skill is not for other platforms, yet the workflow explicitly gathers input from Weibo, Douyin, Pinterest, and Instagram. This inconsistency can mislead users about where data comes from and increases legal, policy, and privacy risk when third-party platform content is collected or repurposed without clear disclosure.
The when-to-run section uses ambiguous examples that do not clearly separate harmless drafting from side-effectful automation. Because this skill can perform web searches, generate images through a paid API, and write local files, unclear scope boundaries can lead to accidental over-execution and unexpected cost or data exposure.
The workflow sends prompts and content to a third-party image-generation API using an API key, but the skill does not warn that user content will leave the local environment. This creates privacy, confidentiality, and billing risk, especially if prompts contain proprietary, personal, or unpublished material.
The skill creates output directories, saves files, and updates history.json, but it does not prominently warn users that local files will be modified. Undisclosed file creation and state mutation are dangerous because they can overwrite data, leak sensitive content into predictable locations, or leave persistent artifacts the user did not expect.
The description states the image generation setup supports Chinese prompts better, and the rest of the configuration is oriented around Chinese-specific aesthetics and platform guidance. In a manifest/config context, this can amount to a locale preference baked into the skill without any visible user opt-in or alternative language/locale path.
The manifest limits the skill to 小红书 content creation and explicitly says it is not for other platforms such as 抖音/微博. However, this configuration defines search keyword templates for 微博热点 and 抖音热点, indicating the skill is designed to gather trend material from those platforms as part of its behavior.
The skill reads the user's ~/.zshrc to recover an API key if the environment variable is absent. Accessing a broad shell profile file is over-privileged for an image helper, risks exposing unrelated secrets/configuration, and normalizes secret scraping from user dotfiles without explicit consent.
All user-facing comments and runtime status/error messages are in Chinese, with no indication that the user can choose another language. This can violate language or locale policy where skills must not force a specific language without user opt-in or documented justification.
This code accesses the DASHSCOPE_API_KEY credential from the process environment and, if missing, falls back to reading ~/.zshrc directly. Although the script prints an error when the key is absent, it does not disclose to the user that it will inspect a shell profile file to obtain a secret.
The file uses shell commands for networking and file operations where direct library calls would suffice. In a content-generation skill, introducing generic shell execution substantially increases risk because any future prompt, URL, or response handling bug can become arbitrary command execution on the user's machine.
The script submits image-generation prompts to a remote DashScope API and includes a bearer token in outbound HTTP requests, then downloads generated images from returned URLs. While progress messages are printed, there is no user-facing disclosure that prompt content and authentication data are being sent to external services.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
]
def submit_task(prompt):
cmd = f'''curl -s "https://dashscope.aliyuncs.com/api/v1/services/aigc/text2image/image-synthesis" \\
-H "Content-Type: application/json" \\
-H "Authorization: Bearer {API_KEY}" \\
-H "X-DashScope-Async: enable" \\
The script builds a shell command string containing both a secret-bearing API key and unescaped prompt text, then executes it with shell=True. Because prompt content is interpolated directly into a single-quoted curl payload, any quote-breaking or shell metacharacters in prompt data could trigger command injection and arbitrary local command execution.
}}
}}'
'''
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
return result.stdout
def get_task_status(task_id):
A secret from the environment or ~/.zshrc is inserted into a shell command and executed. Even if the API key itself is not attacker-controlled, combining credential material with shell execution increases the blast radius of injection bugs and exposes the key to process-level leakage and command-line capture.
}}
}}'
'''
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
return result.stdout
def get_task_status(task_id):
This call executes a shell command assembled with an API key and task_id. In the current flow task_id originates from a remote service response, so a malformed or attacker-controlled value could break command boundaries and execute unintended shell commands on the host.
cmd = f'''curl -s "https://dashscope.aliyuncs.com/api/v1/tasks/{task_id}" \\
-H "Authorization: Bearer {API_KEY}"
'''
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
return result.stdout
def download_image(url, output_path):
The command executed here includes secret-derived data and a remotely sourced task identifier. This creates an unsafe tainted flow from credentials and network-controlled data into shell execution, which can enable command injection or unintended disclosure in logs and process listings.
cmd = f'''curl -s "https://dashscope.aliyuncs.com/api/v1/tasks/{task_id}" \\
-H "Authorization: Bearer {API_KEY}"
'''
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
return result.stdout
def download_image(url, output_path):
No suspicious patterns detected.