Back to skill

Security audit

Feishu Bot

Security checks for vulnerabilities and agentic risk

Overview

This Feishu bot skill mostly matches its stated purpose, but its webhook helper can send caller-supplied content to any URL without validation or clear guardrails.

Install only if you trust the workflows that will call it and can constrain usage to approved Feishu/Lark destinations. Treat message text, approval forms, group membership, and contact data as sensitive, and avoid exposing send_webhook to untrusted prompts or arbitrary URLs without an allowlist and user confirmation.

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_bot.py:267
Finding
Unrestricted Webhook Destination Enables Server-Side Request Forgery## Vulnerability Details **File Location**: `feishu_bot.py:267-274` **Vulnerability Type**: Server-Side Request Forgery (SSRF) and unintended data disclosure **Risk Level**: Medium ```python @staticmethod def send_webhook(webhook_url: str, msg_type: str, content: Union[str, Dict]) -> Dict: """Send message via webhook (no auth required)""" data = { "msg_type": msg_type, "content": {"text": content} if msg_type == "text" else content } resp = requests.post(webhook_url, json=data) return resp.json() ``` ### Technical Analysis The `send_webhook` method passes a caller-controlled `webhook_url` directly to `requests.post`. It does not enforce HTTPS, restrict destinations to documented Feishu webhook domains, validate the resolved IP address, or reject loopback, private, link-local, and reserved network ranges. Redirects are also accepted under the `requests` library's default behavior without revalidating the resulting destination. Although webhook delivery is part of the declared functionality, accepting arbitrary destinations exceeds the minimum network privileges required for a Feishu-specific integration. If an agent derives this parameter from untrusted instructions or message content, an attacker can cause the trusted runtime to send requests to systems that are inaccessible from the attacker's own network position. The request body contains caller-provided message content. Consequently, the same behavior can disclose that content to an unintended or attacker-controlled destination. ### Attack Path 1. An attacker provides an agent with a crafted URL, such as a loopback address, private network service, link-local endpoint, or attacker-controlled redirect. 2. The agent passes that URL to `FeishuBot.send_webhook`. 3. The method performs an HTTP POST from the trusted execution environment without destination validation. 4. The target receives the supplied JSON body and may proc ...[truncated 1032 chars]
Remediation
## Remediation Suggestions - Restrict webhook destinations to documented Feishu/Lark webhook hosts using an exact hostname allowlist. - Require HTTPS and reject URLs containing embedded credentials, unexpected ports, or malformed hostnames. - Resolve the destination before connecting and reject loopback, private, link-local, multicast, unspecified, and reserved IPv4 and IPv6 ranges. - Disable redirects with `allow_redirects=False`, or validate the scheme, hostname, resolved address, and port again for every redirect. - Protect against DNS rebinding by ensuring that validation and connection use a consistently validated destination. - Add an explicit policy or user-confirmation step before permitting delivery to any non-Feishu endpoint. - Apply bounded request timeouts and limit the maximum response size. - Treat webhook content as potentially sensitive and avoid sending it to destinations that have not been explicitly authorized.

T09 · Insecure Skill Coding Practices

Note
Location
feishu_bot.py:32
Finding
Outbound HTTP Requests Lack Timeouts## Vulnerability Details **File Location**: `feishu_bot.py:32-274` **Specific Calls**: `feishu_bot.py:32, 63, 82, 96, 110, 122, 135, 150, 160, 167, 173, 179, 195, 201, 215, 223, 233, 241, 274` **Vulnerability Type**: Unbounded network wait and denial of service **Risk Level**: Low Representative vulnerable request segments include: ```python resp = requests.post(url, json=data) ``` ```python resp = requests.post(url, params=params, headers=self._headers(), json=data) return resp.json() ``` ```python resp = requests.get(url, headers=self._headers()) return resp.json() ``` ```python resp = requests.delete(url, headers=self._headers(), json={"member_id_list": user_ids}) return resp.json() ``` ```python resp = requests.post(webhook_url, json=data) return resp.json() ``` Every `requests.get`, `requests.post`, and `requests.delete` invocation in the module omits the `timeout` parameter. The issue affects token acquisition, messaging, image upload, group administration, approval operations, user-directory queries, and webhook delivery. ### Technical Analysis Python's `requests` library does not impose a default request timeout. Without an explicit timeout, a connection attempt or response read can remain blocked for an indefinite period. A slow, unavailable, or malicious endpoint can therefore retain the worker executing the Skill. The arbitrary webhook method increases exploitability because its destination is caller-controlled. Requests to the fixed Feishu API can also stall due to network outages, DNS failures, degraded upstream service, or incomplete responses. ### Attack Path 1. An attacker causes the workflow to call `send_webhook` with a server under the attacker's control, or with an address that accepts connections but does not complete the response. 2. The server accepts the connection and sends no response, or transmits response data indefinitely slowly. 3. Because no connect or re ...[truncated 734 chars]
Remediation
## Remediation Suggestions - Configure bounded connect and read timeouts on every outbound request, for example: ```python REQUEST_TIMEOUT = (5, 30) resp = requests.post(url, json=data, timeout=REQUEST_TIMEOUT) ``` - Use a shared `requests.Session` or centralized request wrapper so timeout policy is applied consistently. - Catch `requests.Timeout`, `requests.ConnectionError`, and related exceptions, then return a controlled error without exposing credentials or sensitive payloads. - Apply limited exponential-backoff retries only where safe. Avoid automatically retrying non-idempotent operations such as message sending, group creation, approval creation, or cancellation unless idempotency protection is available. - Combine timeouts with webhook destination validation, redirect restrictions, response-size limits, and workflow-level execution deadlines.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (7)

Credential Access

High
Category
Privilege Escalation
Content
self._token_expires_at = 0
    
    def _get_tenant_token(self) -> str:
        """Get or refresh tenant access token"""
        if self._tenant_access_token and time.time() < self._token_expires_at:
            return self._tenant_access_token
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
96% confidence
Finding
The skill documents use of environment variables for credentials and Feishu network API access, but it does not declare any explicit tool scope such as permissions or allowed-tools. That mismatch can cause the agent runtime to grant broader capabilities than reviewers expect, increasing the risk of unauthorized outbound requests or secret access if the skill is invoked in an unsafe context.

External Transmission

Medium
Category
Data Exfiltration
Content
"app_id": self.app_id,
            "app_secret": self.app_secret
        }
        resp = requests.post(url, json=data)
        result = resp.json()
        
        if result.get("code") != 0:
Confidence
80% 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

Medium
Confidence
93% confidence
Finding
The send_rich_text method always formats post content under the zh_cn locale key, which forces a specific language/locale behavior. The file does not offer any user choice or document that this skill is intentionally limited to a Chinese locale context.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The static `send_webhook` method allows posting arbitrary attacker-controlled content to any URL, not just Feishu endpoints. In an agent skill, this broad outbound capability can be abused for data exfiltration or for interacting with unintended third-party services, which exceeds the stated Feishu-specific scope and increases misuse risk.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The webhook feature performs outbound transmission without any built-in disclosure, confirmation, or guardrails indicating that arbitrary content may be sent to an external endpoint. In an agent context, this can hide exfiltration behavior from users and makes accidental or unauthorized data disclosure more likely.

External Transmission

Medium
Category
Data Exfiltration
Content
"msg_type": msg_type,
            "content": {"text": content} if msg_type == "text" else content
        }
        resp = requests.post(webhook_url, json=data)
        return resp.json()
Confidence
95% confidence
Finding
This request sends caller-supplied content to a caller-supplied URL with no validation or restriction. In an agent-integrated environment, that creates a direct exfiltration primitive and can also be used to reach internal or unexpected external services if the runtime has network access.

Static analysis

No suspicious patterns detected.