Back to skill

Security audit

LarkSync Feishu Local Cache

Security checks for vulnerabilities and agentic risk

Overview

This skill has a legitimate Feishu-to-local-cache purpose, but its WSL helper can automatically trust a discovered network endpoint before sending sensitive sync details.

Install only if you trust the local LarkSync backend and understand that the helper can create or run sync tasks. In WSL, prefer explicitly setting a known --base-url and avoid sending cloud folder tokens to automatically discovered non-loopback HTTP endpoints. Use download_only unless you intentionally want local changes uploaded to Feishu.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/larksync_wsl_helper.py:122
Finding

Automatic WSL Endpoint Trust Can Expose Sensitive Synchronization Data

Content
View full analysis
list[tuple[str, str]]: pairs: list[tuple[str, str]] = [ ("localhost", f"http://localhost:{port}"), ("loopback-ipv4", f"http://127.0.0.1:{port}"), ("docker-host-alias", f"http://host.docker.internal:{port}"), ] gateway = _read_default_gateway() if gateway: pairs.append(("default-gateway", f"http://{gateway}:{port}")) for index, ns in enumerate(_read_resolv_nameservers(), start=1): pairs.append((f"resolv-nameserver-{index}", f"http://{ns}:{port}")) ``` ```python def _probe_single(name: str, base_url: str, timeout: float = DEFAULT_TIMEOUT) -> ProbeResult: parsed = urlparse(base_url) host = parsed.hostname or "" port = parsed.port or 80 connect_ok = False health_ok = False status: int | None = None error_text: str | None = None start = time.perf_counter() try: with socket.create_connection((host, port), timeout=timeout): connect_ok = True health_url = f"{base_url.rstrip('/')}{HEALTH_PATH}" req = request.Request(health_url, headers={"Accept": "application/json"}, method="GET") with request.urlopen(req, timeout=timeout) as resp: status = int(resp.getcode()) health_ok = status == 200 ``` ```python def select_reachable_base_url(results: Iterable[ProbeResult]) -> str | None: for item in results: if item.health_ok: return item.base_url return None ``` ```python def ensure_remote_allow_flag(args: list[str]) -> list[str]: base_url = _extract_base_url(args) if not base_url: ...[truncated 4239 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/larksync_skill_helper.py:159
Finding

Unredacted Backend Responses Can Leak Tokens and Authorization Metadata

Content
View full analysis
dict[str, Any]: health = _request_json(base_url=base_url, method="GET", path="/health") auth = _request_json(base_url=base_url, method="GET", path="/auth/status") config = _request_json(base_url=base_url, method="GET", path="/config") tasks = _request_json(base_url=base_url, method="GET", path="/sync/tasks") task_count = len(tasks.data) if tasks.ok and isinstance(tasks.data, list) else 0 connected = bool(auth.data.get("connected")) if auth.ok and isinstance(auth.data, dict) else False return { "base_url": _normalize_base_url(base_url), "health": {"ok": health.ok, "status_code": health.status_code, "data": health.data}, "auth": {"ok": auth.ok, "status_code": auth.status_code, "data": auth.data}, "config": {"ok": config.ok, "status_code": config.status_code, "data": config.data}, "tasks": {"ok": tasks.ok, "status_code": tasks.status_code, "count": task_count, "data": tasks.data}, "ready_for_sync": bool(health.ok and connected), } ``` ```python created = _request_json(base_url=base_url, method="POST", path="/sync/tasks", payload=payload) if created.ok: return {"action": "create-task", "created": True, "task": created.data} if created.status_code == 409: existing = _find_existing_task( base_url=base_url, local_path=local_path, cloud_folder_token=cloud_folder_token, ) if existing: return { "action": "create-task", "created": False, "reason": "task_conflict_reused_existing", "task": existing, "detail": created.data, } ``` ```python print(json.dumps({"ok": True, "result": result}, ...[truncated 2227 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/larksync_skill_helper.py:242
Finding

Bootstrap Workflow Ignores Failed Health and Authorization Checks

Content
View full analysis
dict[str, Any]: check_result = do_check(base_url) config_result = do_configure_download( base_url=base_url, value=download_value, unit=download_unit, daily_time=download_time, ) task_result = do_create_task( base_url=base_url, name=name, local_path=local_path, cloud_folder_token=cloud_folder_token, sync_mode=sync_mode, ) run_result: dict[str, Any] | None = None if run_now: task = task_result.get("task") or {} task_id = str(task.get("id", "")).strip() if task_id: run_result = do_run_task(base_url, task_id) ``` ### Technical Analysis `do_check()` calculates a `ready_for_sync` value based on backend health and the reported authorization connection state. However, `do_bootstrap_daily()` merely stores that check result and proceeds unconditionally to: 1. Modify the download configuration. 2. Create a synchronization task containing the cloud folder token and local path. 3. Optionally execute the task. The readiness check is therefore informational rather than an enforced security gate. This contradicts the documented operational boundary that configuration must stop when Feishu authorization is disconnected and that state-changing actions must not occur before a successful check. This weakness also compounds the unauthenticated WSL endpoint-selection issue: even if a selected service reports that it is unhealthy or unauthorized, the bootstrap flo ...[truncated 1328 chars]
Remediation
View remediation
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (9)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The WSL helper behavior goes beyond simple document sync by probing multiple local/network-reachable endpoints, performing health checks, rewriting CLI arguments, and dynamically invoking another helper module. While likely intended for connectivity troubleshooting, these behaviors expand the attack surface and are under-disclosed, which can surprise users and weaken trust boundaries around where requests are sent.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The WSL helper behavior goes beyond simple document sync by probing multiple local/network-reachable endpoints, performing health checks, rewriting CLI arguments, and dynamically invoking another helper module. While likely intended for connectivity troubleshooting, these behaviors expand the attack surface and are under-disclosed, which can surprise users and weaken trust boundaries around where requests are sent.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill documents commands that perform network access, file operations, and likely environment-dependent behavior, but it does not declare any explicit tool scope or permissions boundary. In an agent setting, this increases the chance of overbroad execution because operators and policy engines cannot easily constrain what the skill is allowed to touch.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The markdown specifies '对用户:简明中文结论 + 下一步操作', which directs the skill to respond to users in Chinese by default. This is a natural-language locale constraint and the file does not indicate that the user can choose another language or opt in to Chinese output.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The helper explicitly permits "bidirectional" and "upload_only" sync modes even though the skill is ներկայացված as Feishu-to-local caching for read-only/OpenClaw-first consumption. This creates a capability mismatch: a user or downstream agent could unintentionally push local content back to Feishu, causing data overwrite, exfiltration, or integrity issues inconsistent with the advertised trust boundary.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Task creation accepts arbitrary sync_mode values from the broader mode set and forwards them to the backend, enabling remote-modifying behavior under a skill described as local cache synchronization. In an agent setting, this discrepancy is dangerous because other components may trust the description and invoke the helper assuming it cannot upload or alter remote documents.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The CLI exposes create-task, run-task, and bootstrap automation for general synchronization workflows rather than a narrowly scoped local-cache helper. That broader operational surface increases the chance that an agent or user will perform state-changing sync actions beyond the intended read-cache use case, especially when combined with upload-capable modes.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

This Python file contains multiple user-facing strings entirely in Chinese, including diagnostics, errors, and usage/help text. The skill does not offer a language selection or indicate that it is intentionally limited to a Chinese-speaking or region-specific environment, which violates the language/locale policy criterion.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

This code presents user-facing validation messages only in Chinese, and the CLI description/help text elsewhere in the file is also Chinese-only. That creates a locale/language constraint without any opt-in or documented justification, which matches the natural-language policy concern for forced language selection.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.