Back to skill

Security audit

Feishu Send Message

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it claims, but it can send Feishu messages using local app credentials with weak scoping and validation.

Install only if you trust the publisher and intend agents to send Feishu messages with local app credentials. Restrict readable ~/.openclaw credential files, allow only intended agent identities and recipient types, avoid sending sensitive content, and prefer adding confirmation, recipient allowlists, and safe JSON construction before routine use.

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 (3)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
send.sh:9
Finding

Unvalidated Agent Identifier Allows Unauthorized Credential Selection

Content
View full analysis

Vulnerability Details

File Location: send.sh, lines 9-34
Vulnerability Type: Missing authorization and input validation
Risk Level: Medium

Vulnerable Code

bash
AGENT=$1
TARGET=$2
MSG_TYPE=$3
MESSAGE=$4

if [ -z "$AGENT" ] || [ -z "$TARGET" ] || [ -z "$MSG_TYPE" ] || [ -z "$MESSAGE" ]; then
    echo "用法:$0 {agent} {target} {msg_type} {message}"
    echo "示例:"
    echo "  $0 ass ou_afa28cfc5689f929f1b1d8f3b09b9408 open_id \"私聊消息\""
    echo "  $0 ass oc_88fbbe55e37eca3c3339b2f4bae1a8a9 chat_id \"群聊消息\""
    echo "  $0 ops ou_xxxxxxxxxxxxxxxxxxxxxxxxxxx open_id \"运维消息\""
    exit 1
fi

# 配置文件路径
CONFIG_FILE="$HOME/.openclaw/openclaw-${AGENT}.json"

if [ ! -f "$CONFIG_FILE" ]; then
    echo "错误:配置文件不存在:$CONFIG_FILE"
    exit 1
fi

# 读取配置
APP_ID=$(jq -r '.channels.feishu.appId' "$CONFIG_FILE")
APP_SECRET=$(jq -r '.channels.feishu.appSecret' "$CONFIG_FILE")

Technical Analysis

The documentation defines the permitted agent values as ass and ops, but the script only checks whether the argument is empty. It directly incorporates the caller-controlled value into a credential configuration filename.

Consequently, a caller can select another existing configuration that follows the openclaw-<agent>.json naming convention, such as a privileged boss configuration. If that file contains the expected Feishu fields and is readable by the process, the script extracts its App ID and App Secret, obtains a tenant token, and sends a message using that application's identity.

The script does not directly disclose the App Secret or transmit it to an unrelated domain. However, it acts as a credential-use oracle that enables operations under an application identity the caller was not intended to select.

Attack Path

  1. An attacker or untrusted agent gains permission to invoke send.sh.
  2. The attacker supplies an undocumented agent identifier corresponding to another ...[truncated 861 chars]
Remediation
View remediation

Remediation Suggestions

Enforce an explicit allowlist before deriving or accessing any configuration path:

bash
case "$AGENT" in
    ass)
        CONFIG_FILE="$HOME/.openclaw/openclaw-ass.json"
        ;;
    ops)
        CONFIG_FILE="$HOME/.openclaw/openclaw-ops.json"
        ;;
    *)
        echo "Invalid agent identifier"
        exit 1
        ;;
esac

Additional hardening should include:

  • Use a fixed mapping rather than concatenating user input into a path.
  • Resolve the canonical path and verify that it exactly matches an approved configuration file.
  • Apply restrictive permissions to credential files, such as owner-only read access.
  • Run separate agents under separate operating-system accounts where practical.
  • Ensure that each runtime identity can read only its own configuration.
  • Add authorization checks at the skill invocation boundary so untrusted agents cannot select application identities.

T09 · Insecure Skill Coding Practices

Warning
Location
send.sh:60
Finding

Unsafe JSON Construction Allows Request Payload Injection and Corruption

Content
View full analysis

Vulnerability Details

File Location: send.sh, lines 60-63
Vulnerability Type: Improper encoding of untrusted data in a JSON request
Risk Level: Medium

Vulnerable Code

bash
RESULT=$(curl -s -X POST "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=${MSG_TYPE}" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d "{\"receive_id\":\"$TARGET\",\"msg_type\":\"text\",\"content\":\"{\\\"text\\\":\\\"$MESSAGE\\\"}\"}")

Technical Analysis

TARGET and MESSAGE are interpolated directly into a manually assembled JSON document without JSON encoding. The message is especially sensitive because it is embedded inside a JSON string that itself contains serialized JSON.

Shell quoting prevents these values from being interpreted directly as shell commands, so this is not a shell command-injection issue. It does not, however, escape quotation marks, backslashes, newlines, control characters, or JSON structural characters for the outgoing request.

A crafted value can therefore terminate or alter the intended JSON string, introduce duplicate or unexpected fields where syntactically possible, or make the request invalid. Even normal messages containing quotation marks, backslashes, or line breaks may be serialized incorrectly.

Attack Path

  1. An attacker controls the target or message argument supplied to the script.
  2. The script inserts that value directly into the JSON request body.
  3. Embedded quotation marks, escape sequences, or structural characters change or invalidate the serialized request.
  4. The Feishu API receives a request that differs from the script author's intended structure.
  5. Depending on the resulting payload and API parsing behavior, the request is rejected or fields and message content are interpreted unexpectedly.

This finding does not establish local command execution because the variables remain inside a quoted shell arg ...[truncated 433 chars]

Remediation
View remediation

Remediation Suggestions

Construct both JSON layers with a serializer rather than string interpolation:

bash
CONTENT=$(jq -nc --arg text "$MESSAGE" '{text: $text}')

BODY=$(jq -nc \
    --arg receive_id "$TARGET" \
    --arg content "$CONTENT" \
    '{receive_id: $receive_id, msg_type: "text", content: $content}')

RESULT=$(curl --fail-with-body --silent --show-error \
    -X POST \
    "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=${MSG_TYPE}" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    --data-binary "$BODY")

Also:

  • Validate recipient IDs against the expected ou_... or oc_... format.
  • Apply a reasonable message-length limit.
  • Reject unsupported control characters if they are not required.
  • Add tests for quotation marks, backslashes, Unicode, line breaks, and empty values.
  • Avoid printing complete message bodies to logs unless explicitly requested.

T09 · Insecure Skill Coding Practices

Note
Location
send.sh:11
Finding

Unvalidated Recipient Type Allows Query Parameter Manipulation

Content
View full analysis

Vulnerability Details

File Location: send.sh, lines 11 and 60-63
Vulnerability Type: Missing allowlist validation for a URL query parameter
Risk Level: Low

Vulnerable Code

bash
MSG_TYPE=$3
bash
RESULT=$(curl -s -X POST "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=${MSG_TYPE}" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d "{\"receive_id\":\"$TARGET\",\"msg_type\":\"text\",\"content\":\"{\\\"text\\\":\\\"$MESSAGE\\\"}\"}")

Technical Analysis

The documented recipient types are open_id and chat_id, but the implementation accepts any nonempty value. The value is placed directly into the request URL without allowlist validation or URL encoding.

Because the complete URL is enclosed in shell quotes, this issue does not permit shell metacharacters to execute commands. However, URL query delimiters such as an ampersand can introduce additional query parameters, and unsupported values can alter or break request behavior.

The URL scheme, host, and path are fixed before the attacker-controlled value, so this issue alone does not allow redirecting the access token to an unrelated host.

Attack Path

  1. An attacker invokes the script with a crafted msg_type value rather than open_id or chat_id.
  2. The value is appended directly after receive_id_type= in the Feishu API URL.
  3. Query delimiters in the input modify the query string sent by curl.
  4. Feishu processes or rejects the manipulated query.
  5. The message request may behave unexpectedly or fail.

Impact Assessment

The primary impact is manipulation or denial of the intended Feishu API request. The destination remains the official Feishu HTTPS endpoint, and this finding does not independently expose credentials or provide local code execution. Its scope is limited to the affected outbound message operation and any behavior supported by additional F ...[truncated 23 chars]

Remediation
View remediation

Remediation Suggestions

Enforce the documented recipient-type allowlist before making any network request:

bash
case "$MSG_TYPE" in
    open_id|chat_id)
        ;;
    *)
        echo "Invalid recipient type"
        exit 1
        ;;
esac

For dynamic query parameters, use URL-aware encoding:

bash
RESULT=$(curl --fail-with-body --silent --show-error \
    --request POST \
    --get \
    --data-urlencode "receive_id_type=$MSG_TYPE" \
    "https://open.feishu.cn/open-apis/im/v1/messages" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    --data-binary "$BODY")

The explicit allowlist should remain the primary control because only two values are functionally supported.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (14)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README promotes automatic outbound reporting to Feishu recipients but does not clearly warn users that the skill can send messages externally on its own. In an agentic environment, this can cause unintended data disclosure, surprise communications to users or groups, and misuse if downstream agents invoke it without explicit user awareness or consent.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
89% confidence
Finding

This section introduces direct curl-based interaction with Feishu, including retrieval of a tenant token using locally stored app credentials. Even though external transmission is the intended feature, it is still security-relevant because it normalizes sending locally sourced secrets and data off-host without guardrails, which can be abused in a broader prompt/agent workflow.

Content

Scanner excerpt · SKILL.md (reported line 37)May include surrounding context.

ops <open_id> open_id "运维消息"

text

### 方法 2:直接使用 curl 命令

```bash
# 读取当前 Agent 配置(以 Ass 为例)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill explicitly instructs users to read Feishu app credentials from local configuration and use them to obtain an access token and send messages to an external service, but it provides no warning, consent boundary, or secret-handling guidance. In an agent skill context, this creates a real risk of credential misuse and unintended data transmission because operators may run the commands blindly with sensitive identifiers and message content.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
95% confidence
Finding

The command sends message content and recipient identifiers to Feishu using an authorization token derived from local credentials. In an agent environment, that is a genuine exfiltration path for user data, internal operational content, and identifiers, especially because the skill encourages direct execution without validating message content, recipient, or approval state.

Content

Scanner excerpt · SKILL.md (reported line 50)May include surrounding context.

md
-d "{\"app_id\":\"$APP_ID\",\"app_secret\":\"$APP_SECRET\"}" | jq -r '.tenant_access_token')

# 发送私聊消息
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\":\"ou_xxx\",\"msg_type\":\"text\",\"content\":\"{\\\"text\\\":\\\"消息内容\\\"}\"}"

External Transmission

Medium
Category
Data Exfiltration
Confidence
96% confidence
Finding

This script reads Feishu app secrets from local configuration and immediately exchanges them for an access token via an external API call. Embedding this pattern in a reusable skill materially increases the risk of credential abuse, accidental disclosure through shell history or debugging, and unauthorized message-sending if the script is invoked in the wrong context.

Content

Scanner excerpt · SKILL.md (reported line 129)May include surrounding context.

md
APP_SECRET=$(jq -r ".channels.feishu.appSecret" ~/.openclaw/openclaw-${AGENT}.json)

# 获取 token
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\"}" | jq -r '.tenant_access_token')

External Transmission

Medium
Category
Data Exfiltration
Confidence
97% confidence
Finding

The script performs an authenticated outbound send using user-supplied target, receive_id_type, and message content with no validation or safety checks. That makes the skill more dangerous in context because it can be repurposed to send unauthorized or sensitive operational content to unintended recipients, and the unsanitized shell/JSON interpolation also increases the chance of malformed requests or misuse when special characters are present.

Content

Scanner excerpt · SKILL.md (reported line 134)May include surrounding context.

md
-d "{\"app_id\":\"$APP_ID\",\"app_secret\":\"$APP_SECRET\"}" | jq -r '.tenant_access_token')

# 发送消息
curl -s -X POST "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=${MSG_TYPE}" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d "{\"receive_id\":\"$TARGET\",\"msg_type\":\"text\",\"content\":\"{\\\"text\\\":\\\"$MESSAGE\\\"}\"}" | jq '.data.message_id'

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The manifest explicitly instructs operators to extract users' Feishu identifiers from systemd journal logs and use them to send messages under agent-controlled app credentials, but it does not clearly warn about privacy, consent, or the operational sensitivity of reading service logs. This can normalize access to potentially sensitive logs and enable message delivery to users or groups without sufficient authorization boundaries or audit guidance.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script prints the App ID during runtime, which exposes identifying credential metadata into terminal history, logs, CI output, or shared session recordings. While an App ID is usually less sensitive than an app secret or access token, disclosing it still assists reconnaissance and may ease correlation of leaked credentials with a specific tenant integration.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · send.sh (reported line 50)May include surrounding context.

sh
# 获取 token
echo "获取 token..."
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\"}" | jq -r '.tenant_access_token')

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · send.sh (reported line 61)May include surrounding context.

sh
# 发送消息
echo "发送消息..."
RESULT=$(curl -s -X POST "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=${MSG_TYPE}" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d "{\"receive_id\":\"$TARGET\",\"msg_type\":\"text\",\"content\":\"{\\\"text\\\":\\\"$MESSAGE\\\"}\"}")

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
75% confidence
Finding

The README content is entirely in Chinese and presents the skill as-is without indicating that users may choose another language or locale. This can constitute a natural-language policy issue when a skill effectively mandates a specific language without documented opt-in or justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The manifest tag zh-CN indicates a locale constraint, but the file does not state that language is user-selectable or explain why the skill is intentionally region- or language-specific. Under the policy, forcing a specific language/locale without opt-in or documented justification is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The script's human-facing description, usage guidance, and runtime messages are written only in Chinese. Under the language/locale policy, this is a natural-language constraint that does not offer opt-in or an alternative language choice.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The inline usage documentation says msg_type is open_id (私聊) 或 chat_id (群聊), which describes target ID types rather than a message type. In the implementation, MSG_TYPE is passed as receive_id_type in the Feishu API request while the actual msg_type is hardcoded to text, so the comment/documentation contradicts how the parameter is used.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.