Back to skill

Security audit

Enable Feishu to send files or images

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed Feishu helper that sends user-specified images or files, but users should treat it as sensitive because it uses local Feishu app credentials and transmits files externally.

Install only if you intend to let the agent use your local Feishu app credentials to upload and send specified files. Before each send, verify the recipient ID, recipient type, and file path, and avoid sending sensitive local files unless that is deliberate.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
feishu_send_message.sh:116
Finding
Temporary Image Copies Are Not Removed After Processing<![CDATA[ ## Vulnerability Details **File Location**: `feishu_send_message.sh`, lines 116–123 **Vulnerability Type**: Unsafe temporary-file lifecycle **Risk Level**: Medium ### Vulnerable Code ```bash TEMP_DIR=$(mktemp -d) TEMP_FILE="$TEMP_DIR/$(basename "$FILE_PATH")" sips -s format jpeg -s formatOptions 80 -z 3000 4000 "$FILE_PATH" --out "$TEMP_FILE" 2>/dev/null || { TEMP_FILE="$FILE_PATH" } FILE_PATH="$TEMP_FILE" echo "✅ 压缩完成" ``` ### Technical Analysis When an image exceeds 10 MB, the script creates a temporary directory and writes a compressed copy of the image into it. No `trap`, cleanup function, or explicit `rm` operation removes this directory after the upload completes or after a later command fails. Although `mktemp -d` normally creates a directory with restrictive permissions, the sensitive image remains on disk after the process terminates. It can subsequently be accessed by processes running as the same operating-system account, privileged local users, backup or indexing software, or any process that later gains access to that account. Repeated executions can also accumulate abandoned files and consume storage. The problem affects successful execution and error paths because the script exits without cleaning up the generated directory. ### Attack Path 1. A user invokes the Skill with an image larger than 10 MB. 2. The script creates a directory under the system temporary-file location. 3. `sips` writes a compressed copy of the image into that directory. 4. The script uploads the copy to Feishu and then exits, or exits early because of an upload or message-delivery error. 5. The temporary directory and image remain on disk. 6. A later process running under the same account, or a privileged local process, enumerates the temporary directory and reads the retained image. ### Impact Assessment This does not provide remote code execution or privilege escalation by itself. Its primary impact is local confidentiality loss involving the conten ...[truncated 276 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Create a cleanup function immediately after creating the temporary directory and register it for all exit paths: ```bash TEMP_DIR="" cleanup() { if [[ -n "$TEMP_DIR" && -d "$TEMP_DIR" ]]; then rm -rf -- "$TEMP_DIR" fi } trap cleanup EXIT INT TERM TEMP_DIR=$(mktemp -d) || { echo "Error: failed to create a temporary directory" >&2 exit 1 } chmod 700 "$TEMP_DIR" ``` Additional hardening measures: 1. Keep the temporary directory private with mode `0700`. 2. Use a fixed generated output name rather than retaining the user-controlled basename. 3. Verify that compression succeeded and that the generated file is within the required size before uploading it. 4. Do not report compression success when `sips` fails. 5. Preserve the cleanup trap for successful execution, command failures, and interruption signals. 6. Where supported, securely manage sensitive temporary data using an application-private runtime directory. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
feishu_send_message.sh:69
Finding
Unescaped Input Is Embedded Directly into API URLs and JSON Request Bodies<![CDATA[ ## Vulnerability Details **File Location**: `feishu_send_message.sh`, lines 69–71 and 145–148 **Vulnerability Type**: Improper input validation and output encoding **Risk Level**: Low ### Vulnerable Code The application credentials are directly interpolated into JSON: ```bash TOKEN_RESPONSE=$(curl -s -X POST "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal" \ -H "Content-Type: application/json; charset=utf-8" \ -d "{\"app_id\":\"$APP_ID\",\"app_secret\":\"$APP_SECRET\"}") ``` The recipient type is directly interpolated into a URL, and the recipient ID is directly interpolated into JSON: ```bash MESSAGE_RESPONSE=$(curl -s -X POST "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=$RECEIVE_ID_TYPE" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json; charset=utf-8" \ -d "{\"receive_id\":\"$RECEIVE_ID\",\"msg_type\":\"image\",\"content\":\"{\\\"image_key\\\":\\\"$IMAGE_KEY\\\"}\"}") ``` The same unsafe message construction is repeated for file messages at lines 194–197: ```bash MESSAGE_RESPONSE=$(curl -s -X POST "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=$RECEIVE_ID_TYPE" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json; charset=utf-8" \ -d "{\"receive_id\":\"$RECEIVE_ID\",\"msg_type\":\"file\",\"content\":\"{\\\"file_key\\\":\\\"$FILE_KEY\\\"}\"}") ``` ### Technical Analysis Values read from configuration and command-line arguments are inserted into serialized JSON without JSON escaping. A value containing a quotation mark, backslash, newline, or another JSON control character can terminate or alter the intended string representation or produce malformed JSON. Similarly, `RECEIVE_ID_TYPE` is inserted directly into the query string without validation or URL encoding. The documentation restricts it to `open_id` or `chat_id`, but the implementation does not enforce that restriction. Query delimiters such as `&` can ...[truncated 1483 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Validate all enumerated arguments before issuing any network request: ```bash case "$RECEIVE_ID_TYPE" in open_id|chat_id) ;; *) echo "Error: receive-id-type must be open_id or chat_id" >&2 exit 1 ;; esac ``` Generate request bodies with a JSON serializer rather than manual string interpolation. For example, with `jq`: ```bash TOKEN_BODY=$(jq -n \ --arg app_id "$APP_ID" \ --arg app_secret "$APP_SECRET" \ '{app_id: $app_id, app_secret: $app_secret}') TOKEN_RESPONSE=$(curl --silent --show-error --fail-with-body \ -X POST \ -H "Content-Type: application/json; charset=utf-8" \ --data-binary "$TOKEN_BODY" \ "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal") ``` Build the nested message content separately: ```bash CONTENT=$(jq -cn --arg image_key "$IMAGE_KEY" '{image_key: $image_key}') MESSAGE_BODY=$(jq -n \ --arg receive_id "$RECEIVE_ID" \ --arg msg_type "image" \ --arg content "$CONTENT" \ '{receive_id: $receive_id, msg_type: $msg_type, content: $content}') ``` Use curl's query encoding rather than URL concatenation: ```bash curl --get \ --data-urlencode "receive_id_type=$RECEIVE_ID_TYPE" \ --request POST \ --data-binary "$MESSAGE_BODY" \ "https://open.feishu.cn/open-apis/im/v1/messages" ``` Also reject control characters in identifiers, verify required argument values exist before accessing `$2`, and use a proper JSON parser to read the configuration and API responses. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (8)

Credential Access

High
Category
Privilege Escalation
Content
exit 1
fi

echo "📤 获取 access token..."

# 获取 tenant_access_token
TOKEN_RESPONSE=$(curl -s -X POST "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal" \
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill uses shell-capable functionality and accesses sensitive local credentials, but it declares no explicit tool scope or permission boundaries. This increases the chance that an agent may invoke shell operations or credential-dependent behavior without adequate policy gating, making unintended file access and outbound actions harder to constrain or audit.

Vague Triggers

Medium
Confidence
92% confidence
Finding
The trigger phrases include broad natural-language intents like “发图片” and “发文件,” which can overlap with ordinary conversation and cause accidental activation. In this skill, accidental activation is more dangerous because the action can exfiltrate local files to an external messaging platform using stored credentials.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill description explains how to read local Feishu credentials and send files/images externally, but it does not clearly warn about the security implications of local secret access and outbound data transfer. This omission can mislead users or orchestrators into treating the action as routine, despite the risk of credential misuse or unintended disclosure of sensitive local files.

External Transmission

Medium
Category
Data Exfiltration
Content
echo "📤 获取 access token..."

# 获取 tenant_access_token
TOKEN_RESPONSE=$(curl -s -X POST "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal" \
    -H "Content-Type: application/json; charset=utf-8" \
    -d "{\"app_id\":\"$APP_ID\",\"app_secret\":\"$APP_SECRET\"}")
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
# 发送图片消息
        echo "📤 发送图片消息..."
        MESSAGE_RESPONSE=$(curl -s -X POST "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=$RECEIVE_ID_TYPE" \
            -H "Authorization: Bearer $TOKEN" \
            -H "Content-Type: application/json; charset=utf-8" \
            -d "{\"receive_id\":\"$RECEIVE_ID\",\"msg_type\":\"image\",\"content\":\"{\\\"image_key\\\":\\\"$IMAGE_KEY\\\"}\"}")
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
# 发送图片消息
        echo "📤 发送图片消息..."
        MESSAGE_RESPONSE=$(curl -s -X POST "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=$RECEIVE_ID_TYPE" \
            -H "Authorization: Bearer $TOKEN" \
            -H "Content-Type: application/json; charset=utf-8" \
            -d "{\"receive_id\":\"$RECEIVE_ID\",\"msg_type\":\"image\",\"content\":\"{\\\"image_key\\\":\\\"$IMAGE_KEY\\\"}\"}")
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Natural-Language Policy Violations

Low
Confidence
96% confidence
Finding
The script's user-facing description and usage text are written only in Chinese, and the rest of the script continues this pattern in error and status messages. This imposes a specific language on users without any opt-in, fallback, or documentation that the tool is intentionally region- or locale-specific.

Static analysis

No suspicious patterns detected.