Back to skill

Security audit

Feishu File Sender

Security checks for vulnerabilities and agentic risk

Overview

The skill is transparent about sending files through Feishu, but it gives broad power to upload any readable local file to a caller-chosen recipient using local app credentials.

Only install this after verifying that the Feishu app credentials are appropriately scoped and that agents using it cannot be tricked into sending sensitive local files. Prefer restricting sends to the current chat, adding confirmation or allowlists, limiting file paths to generated workspace outputs, and fixing the workspace prefix matching before broad deployment.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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

Error
Location
scripts/feishu_file_sender.py:154
Finding

Unrestricted Local File Exfiltration to a Caller-Controlled Feishu Recipient

Content
View full analysis
argparse.Namespace: parser = argparse.ArgumentParser(description="Upload file to Feishu and send") parser.add_argument("--file", required=True, help="Local file path") parser.add_argument("--receive-id", default=None, help="chat_id or open_id") parser.add_argument( "--receive-id-type", default=None, help="chat_id / open_id / user_id (auto-detect if omitted)", ) parser.add_argument( "--file-type", default="stream", help="file_type for upload, default stream", ) return parser.parse_args() def main() -> None: args = parse_args() file_path = Path(args.file) if not file_path.exists(): raise FileNotFoundError(f"File not found: {file_path}") config = load_openclaw_config() agent_id = resolve_agent_id(config) app_id, app_secret = resolve_feishu_account(config, agent_id) receive_id = resolve_receive_id(args.receive_id) receive_id_type = infer_receive_id_type(receive_id, args.receive_id_type) token = get_tenant_access_token(app_id, app_secret) file_key = upload_file(token, file_path, args.file_type) result = send_file_message(token, receive_id, receive_id_type, file_key) print("Send success:", result) ``` ### Technical Analysis The script accepts an arbitrary local path through `--file` and an arbitrary Feishu destination through `--receive-id`. It only verifies that the selected path exists. It does not verify that the path: - Is a regular file. - Is contained within the active agent workspace. - Belongs to a dedicated generated-output directory. - Is not a symbolic link escaping an approved directory. - Represents a file generated during the current task. The recipient is likewise n ...[truncated 1811 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/feishu_file_sender.py:27
Finding

Workspace Prefix Confusion Can Select Another Agent's Feishu Credentials

Content
View full analysis
str: cwd = Path.cwd().resolve() best_match = (0, None) for agent in config.get("agents", {}).get("list", []): workspace = agent.get("workspace") agent_id = agent.get("id") if not workspace or not agent_id: continue workspace_path = Path(workspace).resolve() if str(cwd).startswith(str(workspace_path)): match_len = len(str(workspace_path)) if match_len > best_match[0]: best_match = (match_len, agent_id) if best_match[1]: return best_match[1] raise RuntimeError("Unable to resolve agent id from workspace path") ``` ### Technical Analysis The function determines whether the current working directory is inside an agent workspace using a raw string-prefix comparison: ```python str(cwd).startswith(str(workspace_path)) ``` String prefixes do not enforce filesystem component boundaries. For example, `/work/agent-a-attacker` starts with `/work/agent-a` even though it is a sibling path rather than a child of that workspace. After resolving the wrong agent ID, `resolve_feishu_account()` uses that ID to select an account binding and retrieve its `appId` and `appSecret`. The flaw therefore crosses an authorization boundary: process working-directory naming can influence which agent identity and Feishu credentials are used. ### Attack Path 1. A privileged agent has a configured workspace such as `/work/agent-a`. 2. An attacker creates or selects a working directory such as `/work/agent-a-attacker`. 3. The script is launched from the attacker-controlled directory. 4. The string-prefix test incorrectly treats that directory as part of `/work/agent-a`. 5. The function returns the privi ...[truncated 944 chars]
Remediation
View remediation
best_match[0]: best_match = (match_len, agent_id) ``` Additional hardening should include: 1. Resolve configured workspaces strictly and reject missing or malformed paths. 2. Detect duplicate, overlapping, or ambiguous workspace definitions at configuration load time. 3. Obtain the agent identity from an authenticated execution context rather than inferring it solely from the current working directory. 4. Verify that the resolved agent is authorized to use the selected Feishu account. 5. Fail closed when more than one workspace could match. 6. Add regression tests covering sibling paths such as `/work/agent-a` and `/work/agent-a-attacker`. ]]>

T08 · Insecure Dependencies

Warning
Location
README.md:38
Finding

Unpinned Third-Party Dependency Installation

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (9)

Credential Access

High
Category
Privilege Escalation
Confidence
87% confidence
Finding

The skill is designed to read Feishu app credentials from ~/.openclaw/openclaw.json and use them to obtain an access token for API operations. Even if the stated purpose is legitimate, accessing local secrets is a high-risk capability because compromise of the skill or misuse of its file/network access could expose credentials or enable unauthorized messaging on behalf of the configured Feishu app.

Content

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

md
- `channels.feishu.accounts.*.appId`
- `channels.feishu.accounts.*.appSecret`

这些凭证仅用于获取 tenant access token 并发送文件。技能不会存储或向其他地方传输凭证。

This skill reads Feishu credentials from the local OpenClaw config
(`~/.openclaw/openclaw.json`) on the machine where it runs:

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 116)May include surrounding context.

md
- `channels.feishu.accounts.*.appId`
- `channels.feishu.accounts.*.appSecret`

These values are used only to obtain a tenant access token and send the file.
The skill does not store or transmit credentials anywhere else.

## 备注 | Notes

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 123)May include surrounding context.

md
- `channels.feishu.accounts.*.appId`
- `channels.feishu.accounts.*.appSecret`

These values are used only to obtain a tenant access token and send the file.
The skill does not store or transmit credentials anywhere else.

## 备注 | Notes

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
- `channels.feishu.accounts.*.appId`
- `channels.feishu.accounts.*.appSecret`

These values are used only to obtain a tenant access token and send the file.
The skill does not store or transmit credentials anywhere else.

## 备注 | Notes

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill explicitly performs sensitive actions—reading local configuration, accessing environment-derived identifiers, and making outbound network requests—but does not declare any tool scope or permission boundaries. In an agent ecosystem, that omission weakens reviewability and least-privilege controls, making it easier for a skill to access secrets and exfiltrate files or metadata without clear operator consent.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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 · scripts/feishu_file_sender.py (reported line 72)May include surrounding context.

python
def get_tenant_access_token(app_id: str, app_secret: str) -> str:
    resp = requests.post(
        FEISHU_TOKEN_URL,
        json={"app_id": app_id, "app_secret": app_secret},
        timeout=15,

Tainted flow: 'data' from requests.post (line 130, network input) → requests.post (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/feishu_file_sender.py (reported line 92)May include surrounding context.

python
"file_type": file_type,
            "file_name": file_path.name,
        }
        resp = requests.post(
            FEISHU_UPLOAD_URL,
            headers=headers,
            data=data,

External Transmission

Medium
Category
Data Exfiltration
Confidence
84% confidence
Finding

This call sends a file message to an externally supplied recipient identifier, which is the core purpose of the skill but also a real exfiltration-capable behavior. In the skill context, the danger is elevated because the recipient can come from CLI or environment variables and there is no verification, allowlist, or confirmation that the destination is intended.

Content

Scanner excerpt · scripts/feishu_file_sender.py (reported line 122)May include surrounding context.

python
"msg_type": "file",
        "content": json.dumps({"file_key": file_key}),
    }
    resp = requests.post(
        FEISHU_SEND_MSG_URL,
        headers=headers,
        params=params,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script uploads an arbitrary local file and sends it to a recipient ID with no user-facing confirmation, disclosure, or policy guardrails. In an agent/automation context, this increases the risk of silent exfiltration of sensitive local artifacts such as keys, configs, logs, or generated reports to an unintended Feishu chat or user.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.