Back to skill

Security audit

Feishu Send

Security checks for vulnerabilities and agentic risk

Overview

The skill is openly meant to send files to Feishu, but it gives broad credential-backed upload instructions with unsafe account fallback and injectable shell/Python snippets.

Review before installing. Use only with tightly scoped Feishu credentials, trusted AGENT_NAME values, known recipient IDs, and explicit user approval for each file or media item sent. The credential lookup should be rewritten to pass AGENT_NAME as data, not Python source, and the main-account fallback should be removed or made an explicit authorized choice.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:25
Finding
Python Code Injection Through the AGENT_NAME Environment Variable<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:25-55` **Vulnerability Type**: Python source-code injection through unsafe string interpolation **Risk Level**: High ### Vulnerable Code ```bash get_feishu_creds() { local agent_name="${AGENT_NAME:-main}" local config_file="$HOME/.openclaw/openclaw.json" local app_id app_secret # Attempt to read the current agent's account app_id=$(python3 -c " import json, sys c = json.load(open('$config_file')) accounts = c.get('channels', {}).get('feishu', {}).get('accounts', {}) # First attempt the agent name if '$agent_name' in accounts: print(accounts['$agent_name'].get('appId', '')) elif 'main' in accounts: print(accounts['main'].get('appId', '')) else: print('') " 2>/dev/null) app_secret=$(python3 -c " import json, sys c = json.load(open('$config_file')) accounts = c.get('channels', {}).get('feishu', {}).get('accounts', {}) if '$agent_name' in accounts: print(accounts['$agent_name'].get('appSecret', '')) elif 'main' in accounts: print(accounts['main'].get('appSecret', '')) else: print('') " 2>/dev/null) echo "$app_id $app_secret" } ``` ### Technical Analysis The environment-controlled `AGENT_NAME` value is expanded by the shell directly into two Python programs passed to `python3 -c`. The value is placed inside Python string literals without any escaping or validation: ```python if '$agent_name' in accounts: ``` An attacker who can control `AGENT_NAME` can supply quote characters, line breaks, and Python statements that terminate the intended string and alter the generated program. The resulting statements are evaluated by `python3` with the same operating-system privileges and environment as the agent. This is not limited to selecting another Feishu account. Successful injection can invoke Python modules such as `os` or `subprocess`, read local files, modify files accessible to the agent, or start arbitrary commands. The code is executed twice be ...[truncated 1517 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Never interpolate environment variables or other runtime input into Python source passed through `python3 -c`. - Pass the configuration path and agent name as positional arguments: ```bash app_id=$(python3 - "$config_file" "$agent_name" <<'PY' import json import sys config_file = sys.argv[1] agent_name = sys.argv[2] with open(config_file, encoding="utf-8") as handle: config = json.load(handle) accounts = config.get("channels", {}).get("feishu", {}).get("accounts", {}) account = accounts.get(agent_name) if account is None: raise SystemExit(f"Unknown Feishu account: {agent_name}") print(account.get("appId", "")) PY ) ``` - Apply the same parameterized design when retrieving `appSecret`. - Prefer one Python invocation that returns structured output instead of duplicating credential lookup logic. - Validate `AGENT_NAME` against an explicit allowlist of configured account names. - Reject control characters, line breaks, and unexpected account-name syntax as defense in depth. - Stop execution on lookup or parsing errors instead of suppressing all diagnostic output. - Avoid exposing application secrets in command output or logs; use a protected inter-process mechanism or perform token acquisition inside the same process where practical. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
SKILL.md:12
Finding
Silent Main-Account Credential Fallback Violates Account Isolation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:12-55` **Vulnerability Type**: Fail-open credential selection and cross-account authorization **Risk Level**: Medium ### Vulnerable Code ```text Prefer reading: account configuration corresponding to the current agent name Error-prevention behavior: if it cannot be read, use the main account ``` ```bash get_feishu_creds() { local agent_name="${AGENT_NAME:-main}" local config_file="$HOME/.openclaw/openclaw.json" local app_id app_secret app_id=$(python3 -c " import json, sys c = json.load(open('$config_file')) accounts = c.get('channels', {}).get('feishu', {}).get('accounts', {}) if '$agent_name' in accounts: print(accounts['$agent_name'].get('appId', '')) elif 'main' in accounts: print(accounts['main'].get('appId', '')) else: print('') " 2>/dev/null) app_secret=$(python3 -c " import json, sys c = json.load(open('$config_file')) accounts = c.get('channels', {}).get('feishu', {}).get('accounts', {}) if '$agent_name' in accounts: print(accounts['$agent_name'].get('appSecret', '')) elif 'main' in accounts: print(accounts['main'].get('appSecret', '')) else: print('') " 2>/dev/null) echo "$app_id $app_secret" } ``` ### Technical Analysis When the requested account is missing, misspelled, or otherwise unavailable, the function silently returns the `main` account's application ID and secret. The fallback is applied without checking whether the invoking agent is authorized to use that identity. This is a fail-open access-control design. Account selection is expected to preserve separation between agents, but a lookup failure instead grants access to a potentially more privileged default identity. It also makes configuration errors dangerous: a typo can cause messages and uploaded files to be sent through the wrong Feishu application without notifying the operator. Reading credentials is necessary for the declared message-sending function, but silently ...[truncated 1506 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Fail closed when the explicitly requested account does not exist: ```python account = accounts.get(agent_name) if account is None: raise SystemExit(f"No authorized Feishu account configured for {agent_name!r}") ``` - Remove the automatic fallback to `main`. - If fallback is operationally required, make it an explicit opt-in setting and verify that the requesting agent is authorized to assume the main identity. - Maintain an allowlist mapping agent identities to permitted Feishu account names. - Require explicit recipient and sender-identity confirmation before uploading or sending content. - Log the selected account name without logging the application secret or access token. - Treat missing credentials, malformed configuration, or unknown agents as fatal errors. - Return the application ID and secret through a structured mechanism rather than a space-delimited `echo`, and prevent credentials from appearing in diagnostic output. - Use separate Feishu applications with narrowly scoped API permissions for agents that require different trust levels. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (15)

External Script Fetching

High
Category
Supply Chain
Content
---
name: feishu-send
description: 飞书发送图片/文件/语音。用 curl 调用飞书 API 发送,比 message 工具更可靠。用于需要发送图片、文件、语音到飞书时触发。
---

# Feishu Send
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
---
name: feishu-send
description: 飞书发送图片/文件/语音。用 curl 调用飞书 API 发送,比 message 工具更可靠。用于需要发送图片、文件、语音到飞书时触发。
---

# Feishu Send
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
### Step 2: 获取 token

```bash
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'])")
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
### Step 3: 上传图片获取 image_key

```bash
IMAGE_KEY=$(curl -s -X POST 'https://open.feishu.cn/open-apis/im/v1/images' \
  -H "Authorization: Bearer $TOKEN" \
  -F "image_type=message" \
  -F "image=@/path/to/image.png" \
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
```bash
# 发到群聊
curl -s -X POST 'https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id' \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"receive_id\":\"$CHAT_ID\",\"msg_type\":\"image\",\"content\":\"{\\\"image_key\\\":\\\"$IMAGE_KEY\\\"}\"}"
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
```bash
# 发到群聊
curl -s -X POST 'https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id' \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"receive_id\":\"$CHAT_ID\",\"msg_type\":\"image\",\"content\":\"{\\\"image_key\\\":\\\"$IMAGE_KEY\\\"}\"}"
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
```bash
# 发到群聊
curl -s -X POST 'https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id' \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"receive_id\":\"$CHAT_ID\",\"msg_type\":\"image\",\"content\":\"{\\\"image_key\\\":\\\"$IMAGE_KEY\\\"}\"}"
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
| python3 -c "import json,sys; print(json.load(sys.stdin)['tenant_access_token'])")

# Step 3: 上传图片
IMAGE_KEY=$(curl -s -X POST 'https://open.feishu.cn/open-apis/im/v1/images' \
  -H "Authorization: Bearer $TOKEN" \
  -F "image_type=message" \
  -F "image=@/tmp/screenshot.png" \
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Transmission

Medium
Category
Data Exfiltration
Content
---
name: feishu-send
description: 飞书发送图片/文件/语音。用 curl 调用飞书 API 发送,比 message 工具更可靠。用于需要发送图片、文件、语音到飞书时触发。
---

# Feishu Send
Confidence
88% confidence
Finding
The skill description states that it uses curl to send images, files, and audio to Feishu, confirming that the skill enables external data transmission. In itself this is expected functionality, but without safeguards around what may be sent and to whom, it increases the chance of unauthorized exfiltration from the host environment.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill is explicitly designed to read Feishu app credentials from a local config file and transmit files, images, and audio to an external service, but it does not require any user confirmation, destination validation, or privacy warning. In an agent setting, this creates a meaningful risk of silent data disclosure because arbitrary local content could be uploaded to Feishu using stored credentials.

External Transmission

Medium
Category
Data Exfiltration
Content
### Step 2: 获取 token

```bash
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'])")
Confidence
78% confidence
Finding
This curl call sends APP_ID and APP_SECRET to Feishu to obtain an access token, which is legitimate for API use but still constitutes external transmission of sensitive credentials. If the skill is invoked unexpectedly or with fallback credentials, it can authorize subsequent data exfiltration under a more privileged account.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# 发到群聊
curl -s -X POST 'https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id' \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"receive_id\":\"$CHAT_ID\",\"msg_type\":\"image\",\"content\":\"{\\\"image_key\\\":\\\"$IMAGE_KEY\\\"}\"}"
Confidence
90% confidence
Finding
This message-send call transmits content to a Feishu chat or user and can be used to deliver uploaded material externally. In the context of a skill that can upload local files first, this becomes a direct exfiltration path if recipients are attacker-controlled or mistakenly selected.

External Transmission

Medium
Category
Data Exfiltration
Content
### Step 4: 发送文件消息

```bash
curl -s -X POST 'https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id' \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"receive_id\":\"$CHAT_ID\",\"msg_type\":\"file\",\"content\":\"{\\\"file_key\\\":\\\"$FILE_KEY\\\"}\"}"
Confidence
91% confidence
Finding
This file-message call is part of a workflow that uploads arbitrary local files and then sends them to a chat, making it a straightforward data exfiltration mechanism. Because the skill is marketed as a reliable alternative for sending files, the surrounding context makes misuse easier rather than harder.

External Transmission

Medium
Category
Data Exfiltration
Content
### Step 4: 发送语音

```bash
curl -s -X POST 'https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id' \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"receive_id\":\"$CHAT_ID\",\"msg_type\":\"audio\",\"content\":\"{\\\"file_key\\\":\\\"$FILE_KEY\\\",\\\"duration\\\":$DURATION}\"}"
Confidence
86% confidence
Finding
This call sends audio messages to Feishu using previously uploaded local audio content. While expected for the skill’s purpose, it still enables outbound transfer of local media without any built-in checks on sensitivity, recipient legitimacy, or user consent.

External Transmission

Medium
Category
Data Exfiltration
Content
# Step 4: 发送
CHAT_ID="oc_87d0d49f1f81f9e1b8dd1d5ad5f9ec72"
curl -s -X POST 'https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id' \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"receive_id\":\"$CHAT_ID\",\"msg_type\":\"image\",\"content\":\"{\\\"image_key\\\":\\\"$IMAGE_KEY\\\"}\"}"
Confidence
84% confidence
Finding
The complete example includes a concrete chat ID and demonstrates end-to-end transmission of a local screenshot to a Feishu chat. Providing a ready-made transmission workflow lowers the barrier to sending potentially sensitive local artifacts outside the environment.

Static analysis

No suspicious patterns detected.