Back to skill

Security audit

feishu-user

Security checks for vulnerabilities and agentic risk

Overview

This Feishu document skill is mostly purpose-aligned, but it handles persistent Feishu credentials and document mutation with weak scoping and safeguards, so it belongs in Review before installation.

Install only if you are comfortable granting this skill access to Feishu documents under your user identity. Prefer reducing OAuth scopes to only what you need, avoid passing app secrets on the command line, protect or remove the cached token file after use, and manually confirm document IDs and block IDs before any update or delete operation.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/feishu_token.py:40
Finding
Feishu access and refresh tokens are stored in a plaintext file without enforced restrictive permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/feishu_token.py:40-44`, with sensitive values written at `scripts/feishu_token.py:70-73` and `scripts/feishu_token.py:101-104` **Vulnerability Type**: Plaintext credential storage with insufficient file-permission controls **Risk Level**: High ### Vulnerable Code ```python def _save_config(self): """保存配置""" os.makedirs(os.path.dirname(CONFIG_FILE), exist_ok=True) with open(CONFIG_FILE, "w") as f: json.dump(self.config, f, indent=2) ``` The sensitive values saved by this function include both token types: ```python self.config["access_token"] = token self.config["refresh_token"] = refresh_token self._save_config() ``` ### Technical Analysis The token manager stores reusable Feishu access and refresh tokens in plaintext at `~/.config/claw-feishu-user/config.json`. It does not explicitly create the configuration directory with mode `0700` or the token file with mode `0600`; effective permissions depend entirely on the user's current umask and pre-existing filesystem state. The implementation also opens the path directly without checking whether it is a symbolic link and writes the file in place rather than using a securely created temporary file followed by atomic replacement. This creates additional exposure to local path manipulation and partial-file corruption. An access token permits operations under the authorizing user's identity until expiration. A refresh token is more sensitive because it can be exchanged for new access tokens, potentially extending unauthorized access. ### Attack Path 1. A user obtains or refreshes a Feishu token through `feishu_token.py`. 2. The script writes the access token and refresh token to the plaintext configuration file. 3. The file is created with permissions derived from the environment's umask or retains unsafe pre-existing permissions. 4. Another local account, compromised process, backup agent, or unintended container workload read ...[truncated 814 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create the configuration directory with owner-only permissions: ```python os.makedirs(os.path.dirname(CONFIG_FILE), mode=0o700, exist_ok=True) os.chmod(os.path.dirname(CONFIG_FILE), 0o700) ``` 2. Create a temporary file using secure exclusive creation and mode `0600`, then atomically replace the destination. 3. Verify with `os.lstat()` that the destination is not a symbolic link before writing. 4. Explicitly enforce mode `0600` on existing configuration files. 5. Prefer an operating-system credential store, such as Keychain, Secret Service, Credential Manager, or a dedicated secrets manager, especially for refresh tokens. 6. Avoid storing an access token when it can be generated on demand from a securely stored refresh token. 7. Document token revocation and rotation procedures for users who suspect local disclosure. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/feishu_token.py:136
Finding
Application secrets are accepted through process arguments and token material is disclosed in terminal output<![CDATA[ ## Vulnerability Details **File Location**: `scripts/feishu_token.py:136-137` and `scripts/feishu_token.py:155-167`; related usage instructions at `SKILL.md:166-177` **Vulnerability Type**: Credential exposure through command-line arguments and logs **Risk Level**: Medium ### Vulnerable Code ```python parser.add_argument("--app-id", required=True, help="飞书应用 App ID") parser.add_argument("--app-secret", required=True, help="飞书应用 App Secret") ``` ```python elif args.code: token = manager.get_access_token(args.code) print(f"获取 token 成功: {token[:20]}...") print(f"Token 已保存到: {CONFIG_FILE}") elif args.refresh: token = manager.refresh_access_token() print(f"刷新 token 成功: {token[:20]}...") else: # 尝试获取缓存的 token token = manager.get_cached_token() if token: print(f"缓存的 token: {token[:20]}...") ``` The documented invocation encourages users to place the secret directly in the command line: ```bash python feishu_token.py --app-id YOUR_APP_ID --app-secret YOUR_SECRET --code AUTH_CODE ``` ### Technical Analysis Command-line arguments may be recorded in shell history, process listings, CI/CD logs, terminal session recording, crash reports, and endpoint-monitoring telemetry. Requiring `--app-secret` therefore creates unnecessary exposure of a long-lived application credential. The script also prints the first 20 characters of access tokens. Although this is not the complete token, it is unnecessary credential disclosure and may appear in persistent logs. Token prefixes can support credential correlation and can become more useful when combined with another partial disclosure. ### Attack Path #### Application-secret exposure 1. The user follows the documented command and supplies the app secret through `--app-secret`. 2. The shell records the command in history, or another local process observes the process argument list. 3. A local attacker, monitoring service, or log reader obtains the app secret. 4. If the attack ...[truncated 1070 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not require application secrets through command-line arguments. 2. Load the app secret from an operating-system credential store, a protected environment variable, or an interactive no-echo prompt using `getpass.getpass()`. 3. If environment variables are supported, warn that build logs and environment dumps must not expose them. 4. Remove all token substrings from terminal output. Print only a non-sensitive success message. 5. Mark sensitive values as secrets in CI/CD and automation systems. 6. Update `SKILL.md` so examples do not place secrets directly in shell commands. 7. Rotate the application secret and revoke affected tokens if command histories or logs containing credentials may have been exposed. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
SKILL.md:27
Finding
The documented authorization flow requests search permissions not used by the implemented client<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:27-35`; related scope declaration at `scripts/feishu_token.py:114-123` **Vulnerability Type**: Excessive OAuth permissions and inconsistent scope construction **Risk Level**: Medium ### Vulnerable Code ```markdown Enable these permissions: - `docx:document` - Document operations - `drive:drive.search:readonly` - Cloud drive search - `search:docs:read` - Document search ``` ```text https://accounts.feishu.cn/open-apis/authen/v1/authorize?client_id={YOUR_APP_ID}&response_type=code&redirect_uri={YOUR_REDIRECT_URI}&scope=docx%3Adocument%20drive%3Adrive.search%3Areadonly%20search%3Adocs%3Aread ``` The token script also declares the same scopes, but does not include them in the generated query parameters: ```python def generate_auth_url(self, redirect_uri: str, state: str = None) -> str: """生成授权 URL""" scope = "docx:document drive:drive.search:readonly search:docs:read" params = { "app_id": self.app_id, "redirect_uri": redirect_uri, "state": state or "", "response_type": "code" } query = "&".join([f"{k}={requests.utils.quote(v)}" for k, v in params.items()]) return f"https://accounts.feishu.cn/open-apis/authen/v1/authorize?{query}" ``` ### Technical Analysis The implemented client supports direct document and block operations, but it does not implement cloud-drive search or document search. Consequently, `drive:drive.search:readonly` and `search:docs:read` exceed the permissions needed for the packaged functionality. Broader search scopes increase the usefulness of a stolen token by allowing document discovery and reconnaissance beyond document identifiers already known to the attacker. There is also an implementation inconsistency: `generate_auth_url()` assigns the intended scope string but never inserts `scope` into `params`. Users following the hard-coded documentation receive the broader scopes, while users relying on the script may re ...[truncated 1142 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `drive:drive.search:readonly` and `search:docs:read` from the documented authorization URL unless corresponding search features are implemented and required. 2. Request only the minimum document scope needed for the selected operation. 3. Add `scope` explicitly to the `params` dictionary in `generate_auth_url()` so generated behavior matches the documented and reviewed authorization policy. 4. Use operation-specific or optional scopes where Feishu supports incremental authorization. 5. Explain the purpose and data exposure of every requested scope in the consent documentation. 6. Add tests that parse generated authorization URLs and assert the exact approved scope set. 7. Advise existing users to revoke and reauthorize tokens with reduced permissions. ]]>

other

Note
Location
scripts/feishu_client.py:74
Finding
The documented overwrite operation silently appends content instead of replacing it<![CDATA[ ## Vulnerability Details **File Location**: `scripts/feishu_client.py:74-86` **Vulnerability Type**: Misleading document-mutation semantics **Risk Level**: Low ### Vulnerable Code ```python def write_doc(self, doc_token: str, content: str) -> Dict[str, Any]: """ 写入文档 (覆盖) Args: doc_token: 文档令牌 content: Markdown 内容 Returns: 操作结果 """ # 追加到文档末尾 return self.append_doc(doc_token, content) ``` ### Technical Analysis The method name and documentation represent `write_doc()` as an overwrite operation, but the implementation delegates directly to `append_doc()`. No existing content is removed or replaced. This semantic mismatch can cause callers to believe that stale, incorrect, or sensitive material has been removed when it remains in the document. Repeated calls can also duplicate content and undermine document integrity. ### Attack Path 1. A caller invokes `write_doc()` expecting the existing document to be replaced. 2. The client retrieves the document blocks and appends the supplied content after the final block. 3. Existing content remains intact. 4. The caller assumes the old content was deleted and may share or publish the document. 5. Readers retain access to stale or sensitive information that the caller intended to replace. ### Impact Assessment The issue can cause unintended retention and disclosure of pre-existing document content. It can also produce duplicate or misleading records. Exploitation does not grant additional system or Feishu privileges. The impact is confined to integrity and confidentiality failures in documents on which the caller already has write access. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Implement true overwrite behavior by enumerating and replacing or deleting existing document blocks before inserting the new content. 2. If overwrite cannot be implemented safely with the API, rename the method to clearly indicate append semantics. 3. Update `SKILL.md`, docstrings, API tables, and examples so they accurately describe the mutation performed. 4. Require explicit confirmation before destructive replacement operations. 5. Add integration tests proving that overwrite removes or replaces prior content and that append preserves it. 6. Consider supporting separate, unambiguous methods such as `replace_document_content()` and `append_document_content()`. ]]>
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (26)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description says the skill is for document read/write operations, but the body also performs OAuth flows, token acquisition/refresh, and local credential caching. This mismatch is dangerous because operators may authorize the skill for simple document editing while overlooking that it can collect, refresh, and persist sensitive credentials.

Credential Access

High
Category
Privilege Escalation
Content
---
name: feishu-user
description: Feishu document operations (User Access Token version). Use user access token for authentication. When you need to read, create, write, or append Feishu documents.
---

# Feishishu document operations using useru User
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
---
name: feishu-user
description: Feishu document operations (User Access Token version). Use user access token for authentication. When you need to read, create, write, or append Feishu documents.
---

# Feishishu document operations using useru User
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
---
name: feishu-user
description: Feishu document operations (User Access Token version). Use user access token for authentication. When you need to read, create, write, or append Feishu documents.
---

# Feishishu document operations using useru User
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
client = FeishuClient(user_access_token="u-xxx")
```

## Get User Access Token

### Step 1: Get App Credentials from Feishu Open Platform
Confidence
82% confidence
Finding
The example initializes the client with an inline token placeholder and later instructs users to load tokens from a local config file, normalizing direct handling of bearer tokens in code and local files. In agent settings, this encourages insecure secret handling patterns that can lead to token leakage via source history, logs, prompts, or filesystem exposure.

Intent-Code Divergence

High
Confidence
99% confidence
Finding
The method is documented as overwriting a document, but it actually appends content by delegating directly to append_doc. In an agent context, this semantic mismatch can cause unintended disclosure, duplication, or corruption of sensitive content because callers may rely on overwrite semantics when handling secrets or replacing stale data.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill documents network access, local file reads/writes, and token persistence, but does not declare any tool scope or permissions boundaries. In an agent environment, this increases the chance the skill will be invoked with broader capabilities than users expect, enabling unreviewed external requests and local credential storage.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The activation text is broad enough that the skill may trigger for many generic document-related requests without clearly constraining when it should access user-scoped Feishu data. Overbroad routing increases the likelihood of unnecessary exposure of personal documents and tokens in contexts where a simpler or read-only action would suffice.

External Transmission

Medium
Category
Data Exfiltration
Content
### Step 3: Exchange for Token

```bash
curl -X POST "https://open.feishu.cn/open-apis/authen/v1/access_token" \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "authorization_code",
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The skill advertises overwrite, update, append, and delete operations without warning about destructive effects, persistence, or the possibility of modifying the wrong document/block. In an agent-assisted workflow, this can lead to accidental data loss or unauthorized changes to personal cloud documents.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The manifest description scopes the skill to reading, creating, writing, or appending Feishu documents. The code additionally exposes block-level retrieval, update, and deletion APIs, including destructive deletion of individual blocks, which is a more granular and broader capability than the stated document operations.

External Transmission

Medium
Category
Data Exfiltration
Content
}
        }
        
        resp = requests.put(url, json=payload, headers=self.headers)
        data = resp.json()
        
        if data.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.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
This code file defines a delete operation that permanently removes a document block via an HTTP DELETE request. Although the docstring names the action as deletion, there is no confirmation prompt, cautionary notice, or explicit warning to the caller about the destructive effect.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The skill is described as document operations, but this file adds OAuth token acquisition and refresh logic, expanding the capability surface into credential handling and persistence. That mismatch increases security risk because users may not expect the skill to manage long-lived authentication material, making misuse or overscoped access easier to overlook.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The code writes access and refresh tokens to a predictable local config file in the user's home directory without any access control hardening or encryption. If the host is multi-user, backed up insecurely, or otherwise compromised, these tokens can be stolen and used to access the victim's Feishu data until revoked or expired.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The script posts app_id, app_secret, and auth code to the Feishu token endpoint, which is a sensitive network transmission. This is central to the script's purpose, but there is no explicit disclosure in the usage/help text or docstrings that these secrets will be sent to a remote service.

External Transmission

Medium
Category
Data Exfiltration
Content
"app_secret": self.app_secret
        }
        
        resp = requests.post(url, json=payload)
        data = resp.json()
        
        if data.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.

External Transmission

Medium
Category
Data Exfiltration
Content
"app_secret": self.app_secret
        }
        
        resp = requests.post(url, json=payload)
        data = resp.json()
        
        if data.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.

External Transmission

Medium
Category
Data Exfiltration
Content
"app_secret": self.app_secret
        }
        
        resp = requests.post(url, json=payload)
        data = resp.json()
        
        if data.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.

External Transmission

Medium
Category
Data Exfiltration
Content
"app_secret": self.app_secret
        }
        
        resp = requests.post(url, json=payload)
        data = resp.json()
        
        if data.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.

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

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

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

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

Missing User Warnings

Medium
Confidence
96% confidence
Finding
At this point the script persists both access and refresh tokens locally without explicit user warning or consent, creating a silent credential retention risk. Refresh tokens are especially sensitive because they can mint new access tokens, so theft of the config file can lead to durable account access.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The refresh flow sends refresh_token, app_id, and app_secret to the remote refresh endpoint. While expected for token refresh, the script does not clearly warn in advance that locally stored credentials will be transmitted over the network during this operation.

Natural-Language Policy Violations

Low
Confidence
87% confidence
Finding
Natural-language guidance in this file is exclusively Chinese, including the module description and usage instructions. Under the stated policy, forcing one language without opt-in or justification can be a locale/language policy issue.

Static analysis

No suspicious patterns detected.