Back to skill

Security audit

Feishu Contacts

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it claims, but it syncs and stores an organization-wide Feishu directory locally without enough privacy, permission, or retention safeguards.

Install only if the Feishu app is authorized to read the relevant directory and the local machine can safely store employee contact data. Before use, restrict ~/.openclaw permissions, treat the cache as sensitive, periodically delete stale cache data, and avoid bulk department lookups unless they are necessary and approved.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/feishu-contacts.py:124
Finding
Organization-Wide Contact Data Is Cached Without Secure File Controls<![CDATA[ ## Vulnerability Details **File Location**: `scripts/feishu-contacts.py`, lines 7 and 105–139 **Vulnerability Type**: Insecure storage of sensitive contact data and unsafe file creation **Risk Level**: Medium ### Vulnerable Code ```python CACHE_FILE = os.path.expanduser("~/.openclaw/.feishu-contacts-cache.json") ``` ```python for u in resp.get("data", {}).get("items", []): oid = u.get("open_id") if oid: dept_users[dept_id].append(oid) if oid not in all_users: name = u.get("name", "") py_full, py_init = to_pinyin(name) all_users[oid] = { "name": name, "open_id": oid, "email": u.get("email", ""), "en_name": u.get("en_name", ""), "pinyin": py_full, "pinyin_initials": py_init, "departments": [] } all_users[oid]["departments"].append(dept_id) # 3. Save cache cache = { "synced_at": time.strftime("%Y-%m-%d %H:%M:%S"), "users": list(all_users.values()), "departments": list(all_depts.values()), "dept_users": dept_users } with open(CACHE_FILE, "w") as f: json.dump(cache, f, ensure_ascii=False, indent=2) ``` ```python def load_cache(): if not os.path.exists(CACHE_FILE): print("No cache found. Run 'sync' first.", file=sys.stderr); sys.exit(1) with open(CACHE_FILE) as f: return json.load(f) ``` ### Technical Analysis The synchronization command retrieves and persistently stores names, email addresses, Feishu Open IDs, English names, department identifiers, and department-membership mappings for the organization. The cache is created through `open(CACHE_FILE, "w")`, so its effective permissions depend on the process umask. The code does not explicitly enforce owner-only permissions such as `0600`. The implementation also performs no ownership, regular-file, or symbolic-link validation before opening the cache. Python's normal file opening behavior follows sy ...[truncated 1958 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Ensure `~/.openclaw` exists, is owned by the current user, and has mode `0700`. 2. Create the cache with owner-only mode `0600`, independent of the process umask. 3. Reject symbolic links and non-regular files. On supported platforms, use `os.open` with `O_NOFOLLOW`, `O_CREAT`, `O_EXCL`, and an explicit `0o600` mode. 4. Write to a securely created temporary file in the same directory, flush and `fsync` it, and then use `os.replace` for atomic publication. 5. Verify the ownership and permissions of an existing cache before reading it. 6. Minimize cached fields. If local search does not require email addresses, omit them and retrieve them only through the live `get` command. 7. Consider encrypting the cache at rest when the threat model includes local filesystem access. 8. Add retention controls and provide a command to securely remove stale cached directory information. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:8
Finding
Third-Party Python Dependency Is Not Version or Hash Pinned<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, line 8 **Vulnerability Type**: Unpinned third-party dependency **Risk Level**: Low ### Vulnerable Code ```yaml metadata: openclaw: emoji: "📇" requires: bins: ["python3"] pips: ["pypinyin"] ``` ### Technical Analysis The Skill declares `pypinyin` without a fixed version or package hash. Installation therefore resolves whichever release satisfies the package name at installation time. This makes installations non-reproducible and allows the effective dependency code to change after the Skill itself has been reviewed. No evidence indicates that `pypinyin` is currently malicious, misspelled, or obtained from an untrusted index. The risk arises from unrestricted future dependency resolution: compromise of the package, its maintainer account, or the package index could cause malicious code to be installed or imported under the privileges of the user running the Skill. ### Attack Path 1. A malicious actor compromises the dependency's release process, maintainer account, or configured package index. 2. The actor publishes a malicious release under the expected `pypinyin` package name. 3. A new installation or dependency refresh resolves the unpinned package to that release. 4. Malicious package code executes during installation or when `to_pinyin()` imports `pypinyin`. 5. The dependency gains the same local access as the Skill process, potentially including access to the Feishu configuration and cached contact information. This path depends on an external supply-chain compromise; no active compromise was identified in the audited files. ### Impact Assessment A compromised dependency would execute with the privileges of the account installing or running the Skill. It could read `~/.openclaw/openclaw.json`, obtain Feishu application credentials, access the contact cache, alter user-owned files, or make arbitrary network requests. The maximum local scope is limited by the ope ...[truncated 151 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `pypinyin` to a specifically reviewed version. 2. Where supported by the Skill installation mechanism, require an approved distribution hash. 3. Install dependencies from a trusted, explicitly configured package index using TLS. 4. Use a lock file or constraints file to make dependency resolution reproducible. 5. Review release notes and security advisories before updating the pinned version. 6. Test dependency updates in an isolated environment before deployment. 7. Run the Skill under a least-privileged account and restrict access to Feishu credentials and cached personal data. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
Findings (7)

Lp3

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding
The skill clearly instructs the agent to perform network access to Feishu APIs and write a persistent local cache file, yet it declares no explicit tool scope such as permissions or allowed-tools. That mismatch weakens least-privilege controls and can cause the agent runtime or reviewer to underestimate what the skill can do, including retrieving and storing employee directory data.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The documentation states that the skill fetches live employee details and persists a local cache containing users, departments, and mappings, but it provides no privacy warning, retention guidance, or handling restrictions for this personal data. In practice, this can lead to over-collection, unnecessary exposure of employee contact information, and unsafe downstream use of emails, phone numbers, and org data.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
Although described as a search skill, the code performs a full organizational directory crawl by enumerating all departments and users, then builds a complete local dataset. This creates a much larger data access footprint than a targeted lookup tool and increases the blast radius if the host is compromised or the skill is misused for bulk employee enumeration.

Context-Inappropriate Capability

Medium
Confidence
98% confidence
Finding
The script persistently stores a complete directory cache under the user’s home directory, including user identifiers, names, emails, department membership, and related metadata. Persistent bulk storage of directory data creates a standing privacy and security risk, especially if file permissions are weak, backups are exposed, or other local processes can read the cache.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The sync workflow writes a local file containing organization contact data but only emits a generic success message, without clearly warning that employee directory information is being persisted on disk. Lack of transparency can cause users to trigger bulk local retention of sensitive data without informed consent, increasing accidental policy violations and privacy exposure.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The manifest frames the skill as a contact lookup utility for open_id, email, and department info, but the live `get` command also retrieves and prints additional personal data such as union_id, enterprise_email, and mobile. This broadens data exposure beyond the declared scope, increasing privacy risk and making it easier for downstream users or agents to access unnecessary sensitive employee information.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
Most operational instructions, command explanations, and mandatory workflow guidance are presented only in Chinese, with no indication that users can choose another language. SQP-3 applies to natural-language policy violations when a skill forces a specific language without user opt-in.

Static analysis

No suspicious patterns detected.