Back to skill

Security audit

Feishu Media Sender

Security checks for vulnerabilities and agentic risk

Overview

This Feishu media sender mostly does what it says, but its credential selection and file validation are loose enough that users should review it before installing.

Install only if you trust the workspace and Feishu configuration it will run under. Before use, verify the recipient, selected file, and account binding; avoid sensitive paths; and prefer a version that fails closed on unmatched agents, uses path-aware workspace checks, rejects non-media files, enforces size limits, and asks for confirmation before upload.

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

Error
Location
scripts/feishu_send_media.py:91
Finding

Unmatched agents can silently inherit an unrelated Feishu account

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/feishu_send_media.py:45
Finding

String-prefix workspace matching permits incorrect agent identity resolution

Content
View full analysis
str: cwd = Path.cwd().resolve() best_match = (0, None) defaults_ws = config.get("agents", {}).get("defaults", {}).get("workspace") if defaults_ws: defaults_path = Path(defaults_ws).resolve() if str(cwd).startswith(str(defaults_path)): best_match = (len(str(defaults_path)), "__defaults__") 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) ``` ### Technical Analysis The function determines whether the current directory is inside an agent workspace by converting both paths to strings and calling `startswith()`. String-prefix matching does not enforce filesystem component boundaries. For example, if an authorized workspace is `/work/agent`, then `/work/agent-evil` also starts with `/work/agent`, despite being a separate sibling directory. Execution from the sibling directory can therefore be incorrectly attributed to the authorized agent. This identity-resolution error becomes an authorization vulnerability because the resulting agent identifier is used to select Feishu application credentials. Combined with the script's ability to upload arbitrary caller-selected files and choose a recipient, incorrect workspace matching may let an untrusted workspace act using another agent's Feishu privileges. ### Attack Path 1. A victim agent has a configured workspace ...[truncated 1274 chars]
Remediation
View remediation
bool: return path == parent or path.is_relative_to(parent) ``` - Alternatively, use `path == parent or parent in path.parents`. - Continue resolving both paths before comparison to normalize relative components and symlinks. - Fail closed if multiple workspace definitions resolve ambiguously. - Add regression tests for sibling paths such as `/work/agent` and `/work/agent-evil`. - Ensure account authorization is independently verified after agent resolution rather than treating path-derived identity as sufficient authorization. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/feishu_send_media.py:125
Finding

Insufficient file validation creates a local-file disclosure primitive

Content
View full analysis
str: if explicit: return explicit.lower() ext = file_path.suffix.lower() if ext in IMAGE_EXTENSIONS: return "image" if ext in VIDEO_EXTENSIONS: return "video" # Default to image for unknown extensions return "image" ``` ```python def main() -> None: args = parse_args() file_path = Path(args.file) if not file_path.exists(): raise FileNotFoundError(f"File not found: {file_path}") media_type = detect_media_type(file_path, args.type) 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) ``` The selected path is subsequently opened and transmitted: ```python with file_path.open("rb") as f: resp = requests.post( FEISHU_IMAGE_UPLOAD_URL, headers=headers, data={"image_type": "message"}, files={"image": (file_path.name, f)}, timeout=60, ) ``` ### Technical Analysis The script only checks whether the supplied path exists. It does not enforce that the path: - Is an approved image or video format. - Has a MIME type or file signature consistent with its extension. - Is a regular file. - Is within an authorized workspace or media directory. - Is not a symlink to a sensitive file. - Complies with the documented 10 MB image or 30 MB video limits. Unknown extensions are explicitly treated as images. A caller can also force the type with `--type image` or `--type video`. Consequently, any readable regular file can reach the HTTP upload attempt, even when it is not media. The Feishu API may reject unsupported content, but ...[truncated 1855 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (5)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill clearly describes behavior that reads local files, accesses credentials from the local configuration, and sends data over the network to Feishu, but it does not declare any explicit tool scope or permissions boundary. In an agent ecosystem, this weakens user visibility and enforcement around sensitive capabilities, increasing the chance that local files or tokens are accessed and exfiltrated without informed consent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The quick-start and description explain how to send media but do not prominently warn that a local file is uploaded to a third-party service and then delivered into a Feishu chat. This creates a meaningful risk of accidental disclosure of sensitive images/videos, especially because users may treat a local path argument as a purely local operation rather than external transmission.

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_send_media.py (reported line 105)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,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This code uploads a user-specified local file to Feishu and then sends it as a message via external HTTP APIs. Although the network behavior is visible in code, there is no confirmation prompt, explicit disclosure in the CLI output, or warning in the module docstring that local file contents and recipient identifiers will be transmitted to a remote service.

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_send_media.py (reported line 194)May include surrounding context.

python
"msg_type": msg_type,
        "content": content,
    }
    resp = requests.post(
        FEISHU_SEND_MSG_URL,
        headers=headers,
        params=params,