T09 · Insecure Skill Coding Practices
- Location
SKILL.md:48- Finding
Shell Command Injection in the Documented AI Invocation Pattern
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is mostly aligned with sending files and images through Feishu, but it handles application secrets and shell commands in ways that could expose credentials or run unintended commands.
Review before installing. Use only with a Feishu/Lark app whose permissions are limited to the intended messaging scope, avoid putting app_secret in prompts, shell history, or command-line arguments, and require a clear user-approved file path and recipient before sending anything. Prefer a safer version that reads secrets from a protected channel and invokes scripts with argument arrays rather than string-built exec commands.
SKILL.md:48Shell Command Injection in the Documented AI Invocation Pattern
scripts/send_file.py:58Application Secret Exposed Through Command-Line Arguments
SKILL.md:32Documentation Instructs Users to Print the Application Secret
代码与声明的前半部分一致,即先上传普通文件再发送文件消息。但声明中特别强调了一个额外的可靠补救场景:当本地图片路径被错误显示为文本路径时,应该改用稳定图片上传脚本,通过 im/v1/images 上传并获得 image_key,再以图片消息发送。实际代码中完全没有图片类型检测、图片上传接口调用、image_key 处理或 msg_type=image 发送逻辑。因此,声明描述了一个重要能力,而代码并未实现,属于描述与实际行为不一致。
声明把该技能定位为‘飞书发送文件技能’,包含两部分能力:1)发送普通文件附件;2)当本地图片路径被错误显示为路径文本时,使用稳定图片上传脚本发送图片。实际提供的代码块只覆盖第 2 部分补救场景,而且是一个专用图片发送脚本 send_image.py。它调用的是飞书图片接口 im/v1/images,返回 image_key,随后发送 msg_type=image 消息;并未涉及普通文件上传接口、file_key、或 msg_type=file 等文件发送逻辑。因此,代码实际行为仅是声明中的一个子场景,不能支撑声明中更广泛的“发送普通文件附件”这一核心能力,构成明显的描述与实现不一致。
The skill explicitly tells the AI to retrieve an application secret from a local configuration file and use it for outbound messaging. That creates a direct path from local secret storage to model-directed use, which is dangerous because the agent may access secrets outside the user's immediate awareness and then transmit data externally.
Passing the secret as an interpolated value inside an exec command materially increases exposure risk because the full command may be captured in logs, stack traces, agent traces, or error messages. Combined with network transmission features, this can enable credential theft and unauthorized use of the Feishu app.
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.
Step 1 - 上传文件:
TOKEN=$(curl -s -X POST "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal" \
-H "Content-Type: application/json" \
-d '{"app_id":"<APP_ID>","app_secret":"<APP_SECRET>"}' | python3 -c "import json,sys; print(json.load(sys.stdin)['tenant_access_token'])")
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.
-H "Content-Type: application/json" \
-d '{"app_id":"<APP_ID>","app_secret":"<APP_SECRET>"}' | python3 -c "import json,sys; print(json.load(sys.stdin)['tenant_access_token'])")
FILE_KEY=$(curl -s -X POST "https://open.feishu.cn/open-apis/im/v1/files" \
-H "Authorization: Bearer $TOKEN" \
-F "file_type=stream" \
-F "file_name=<文件名>" \
The skill clearly instructs use of shell commands and network access to Feishu APIs, but it declares no explicit tool scope or permission boundary. In an agent environment, missing scope declarations can cause overbroad execution capability and make secret access plus outbound transmission easier than intended.
The documentation instructs operators to retrieve app credentials directly from a local config file and use them for network requests, but gives no warning about secret sensitivity, audit logging, or least-privilege handling. This increases the chance that an agent or user will expose secrets in terminal history, transcripts, or logs while exfiltrating local data to an external service.
The AI usage example encourages interpolating sensitive values such as app_secret, recipient identifiers, and file paths directly into an executed command string. In agent systems, this can leak credentials through logs, debugging output, prompt traces, shell history, or accidental command injection surfaces.
The manual curl workflow sends application credentials and local file contents to external Feishu endpoints without any explicit user-consent or data-transfer warning. In a skill context, omission of such warnings makes accidental external disclosure more likely, especially when acting on local files under /root or workspace paths.
This is a real external transmission path: app credentials are posted to Feishu to obtain a tenant token. The transmission itself is expected for the feature, but in a skill environment it is security-relevant because it moves secrets off-host and enables subsequent authenticated actions against a third-party service.
Step 1 - 上传文件:
TOKEN=$(curl -s -X POST "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal" \
-H "Content-Type: application/json" \
-d '{"app_id":"<APP_ID>","app_secret":"<APP_SECRET>"}' | python3 -c "import json,sys; print(json.load(sys.stdin)['tenant_access_token'])")
This command sends a message payload to Feishu containing a recipient identifier and file reference, which is a genuine external data transmission. In context this is the intended business function, but it still represents a disclosure channel and should be treated as a controlled, user-authorized action.
Step 2 - 发送消息:
curl -s -X POST "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"receive_id\":\"<OPEN_ID>\",\"msg_type\":\"file\",\"content\":\"{\\\"file_key\\\":\\\"$FILE_KEY\\\"}\"}"
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def upload_file(token, file_path, file_name):
"""上传文件到飞书,返回 file_key"""
import subprocess
result = subprocess.run([
"curl", "-s", "-X", "POST",
"https://open.feishu.cn/open-apis/im/v1/files",
"-H", f"Authorization: Bearer {token}",
This skill sends a local file and application credentials to remote Feishu services without any explicit confirmation, disclosure prompt, or scoping guardrails. In an agent-skill context, that increases the risk of unintended exfiltration of sensitive local files or misuse of provided credentials, especially because the skill is designed to transmit arbitrary attachments.
The script requires app_id and especially app_secret to be supplied on the command line, which can expose credentials through shell history, process listings, job control logs, audit tooling, or orchestration telemetry. In an agent or shared-host environment, this is more dangerous because secrets may be visible to other local users, logged by wrappers, or captured in task traces.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def upload_image(base: str, token: str, image_path: str) -> str:
result = subprocess.run([
"curl", "-sS", "-X", "POST",
f"{base}/open-apis/im/v1/images",
"-H", f"Authorization: Bearer {token}",
The manifest description is entirely written in Chinese and does not indicate that users may choose another language or that the skill is intended only for a Chinese-language or region-specific context. This can violate language/locale policy when a skill effectively imposes a specific language without opt-in.
Natural-language strings in the module docstring and console output are presented only in Chinese, which imposes a specific language on users without opt-in. Under the policy, forced language or locale is a violation unless the skill offers a choice or clearly justifies the restriction.
No suspicious patterns detected.