Back to skill

Security audit

feishu-quick-setup

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to do what it says, but it handles long-lived Feishu app secrets in ways that could expose them locally.

Review before installing. Use this only on a trusted single-user machine or after tightening file permissions, because it creates a Feishu app and stores its app secret locally. After setup, verify Feishu permissions manually, avoid granting broad document/drive/calendar/contact scopes unless needed, and rotate the app secret if it may have appeared in command logs.

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

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:78
Finding
Feishu application secret exposed through command-line arguments<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:78-80`, `quick-setup.js:58-60`, `quick-setup.mjs:57-59` **Vulnerability Type**: Sensitive credential exposure through process arguments **Risk Level**: Medium ### Vulnerable Code `SKILL.md:78-80`: ```bash node "{script_dir}/quick-setup.mjs" --save --app-id "APP_ID" --app-secret "APP_SECRET" --domain "feishu" ``` `quick-setup.mjs:57-59`: ```js case '--device-code': result.deviceCode = argv[++i]; break; case '--app-id': result.appId = argv[++i]; break; case '--app-secret': result.appSecret = argv[++i]; break; ``` The equivalent CommonJS implementation appears in `quick-setup.js:58-60`: ```js case '--device-code': result.deviceCode = argv[++i]; break; case '--app-id': result.appId = argv[++i]; break; case '--app-secret': result.appSecret = argv[++i]; break; ``` ### Technical Analysis The documented setup workflow instructs the agent to pass the newly issued Feishu application secret as a command-line argument. Both script variants then read that secret directly from `process.argv`. Command-line arguments are not an appropriate transport mechanism for long-lived credentials. Depending on the operating system and execution environment, arguments may be exposed through: - Process inspection interfaces and process-listing tools. - Agent command execution records. - Shell history or terminal session recording. - Audit, telemetry, debugging, and monitoring systems. - Error reports that capture the invoked command. - Other local users or processes with sufficient process-inspection access. Although the scripts do not transmit the app secret to an unrelated network destination, this local exposure is unnecessary. The secret is received from the official Feishu or Lark registration endpoint and should be transferred directly into protected storage without being interpolated into another command. ### Attack Path 1. A user authorizes creation of a new Feishu application. 2. The p ...[truncated 1449 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `--app-secret` from the documented and implemented command-line interface. 2. Accept the secret through standard input or a dedicated inherited file descriptor. Ensure that the agent execution layer does not log the input. 3. Prefer a single operation that polls for the credentials and writes them directly to protected configuration, so the secret never needs to be returned to and reinserted by the agent. 4. If a temporary credential file is unavoidable: - Create it with mode `0o600`. - Place it in a private directory with mode `0o700`. - Open it using exclusive creation semantics. - Delete it immediately after use. 5. Add explicit redaction of `appSecret`, `client_secret`, and equivalent fields to command logs, error reports, and diagnostic output. 6. Update both `quick-setup.js` and `quick-setup.mjs` together to prevent the fallback implementation from retaining the vulnerable interface. 7. Rotate any application secret that may already have been captured in command or agent execution logs. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
quick-setup.mjs:89
Finding
Sensitive registration state and persistent credentials written without restrictive file permissions<![CDATA[ ## Vulnerability Details **File Location**: `quick-setup.mjs:89-91`, `quick-setup.mjs:280-282`, `quick-setup.js:87-89`, `quick-setup.js:278-280` **Vulnerability Type**: Insecure storage of sensitive data **Risk Level**: Medium ### Vulnerable Code `quick-setup.mjs:89-91`: ```js function savePendingState(data) { fs.writeFileSync(PENDING_FILE, JSON.stringify(data, null, 2), 'utf8'); } ``` The data written to this file is assembled at `quick-setup.mjs:397-403`: ```js savePendingState({ deviceCode: result.deviceCode, domain: result.domain, verificationUrl: result.verificationUrl, createdAt: Date.now(), }); ``` Persistent configuration is written at `quick-setup.mjs:280-282`: ```js fs.writeFileSync(configPath, JSON.stringify(cfg, null, 2), 'utf8'); ``` Before that write, the configuration receives the application secret at `quick-setup.mjs:268-272`: ```js cfg.channels.feishu.appId = appId; cfg.channels.feishu.appSecret = appSecret; cfg.channels.feishu.domain = domain || 'feishu'; cfg.channels.feishu.enabled = true; ``` The CommonJS fallback contains equivalent writes at `quick-setup.js:87-89` and `quick-setup.js:278-280`: ```js function savePendingState(data) { fs.writeFileSync(PENDING_FILE, JSON.stringify(data, null, 2), 'utf8'); } ``` ```js fs.writeFileSync(configPath, JSON.stringify(cfg, null, 2), 'utf8'); ``` ### Technical Analysis Neither script specifies a restrictive file mode when creating `.pending.json` or `openclaw.json`. Their effective permissions therefore depend on Node.js defaults and the process umask. The pending-state file contains a live device code and complete verification URL. The OpenClaw configuration contains the persistent Feishu application secret. In an environment with a permissive umask, newly created files may be readable by other local users. Existing configuration files with insecure permissions are also rewritten without first repairing their mode. The script additionally creates a bac ...[truncated 2638 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create the OpenClaw directory with mode `0o700`: ```js fs.mkdirSync(dir, { recursive: true, mode: 0o700 }); fs.chmodSync(dir, 0o700); ``` 2. Create or replace sensitive files with mode `0o600`. Use an atomic write pattern with a private temporary file: ```js const tempPath = `${configPath}.tmp-${process.pid}`; fs.writeFileSync(tempPath, JSON.stringify(cfg, null, 2), { encoding: 'utf8', mode: 0o600, flag: 'wx', }); fs.chmodSync(tempPath, 0o600); fs.renameSync(tempPath, configPath); fs.chmodSync(configPath, 0o600); ``` 3. Apply the same protection to `.pending.json`, and use exclusive creation to reduce race and link-based attacks. 4. Store pending state under a private per-user runtime or configuration directory rather than inside the installed Skill directory. 5. Remove the pending file on success, denial, expiration, timeout, interruption, and unexpected exceptions. Register cleanup handlers where appropriate. 6. Avoid storing the full verification URL if the device code alone is sufficient for polling. 7. Explicitly set and verify mode `0o600` on `openclaw.json.bak`, or avoid creating plaintext credential backups. If backups are required, define retention and secure deletion policies. 8. Reject symbolic-link destinations and validate custom `--config` paths before writing sensitive content. 9. Apply identical changes to both the CommonJS and ES module variants. 10. Add automated tests that execute under a permissive umask and verify that every credential-bearing file is accessible only to its owner. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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 (9)

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill instructs execution of Node scripts that perform external Feishu registration and local credential persistence, but the manifest does not declare any tool scope or permissions boundary. This creates a transparency and policy-enforcement gap: an agent may invoke network-capable code and write secrets to local config without an explicit capability declaration or user-facing guardrails.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The description says the skill creates a Feishu app but does not prominently warn that newly issued app credentials will be saved to a local OpenClaw config file. This weakens informed consent around secret handling and local persistence, increasing the risk that users authorize storage of sensitive credentials without understanding where they will be written.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The trigger list includes an open-ended 'etc.', making activation criteria ambiguous and potentially broader than intended. In an agent setting, this can cause the skill to run on loosely related user requests, leading to unintended app creation, external authorization prompts, or credential writes.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The message states that '基础权限(消息收发等)已默认开启', implying the created Feishu app has remote permissions enabled. However, this function only updates local openclaw.json fields and does not call any API to grant or enable Feishu app permissions. This is an active contradiction between the inline/user-facing documentation text and the code's actual behavior.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The returned user-facing message is entirely in Chinese string literals, which forces a specific language for successful setup output. The file does not provide any user opt-in, locale selection, or justification that this skill is intended only for Chinese-speaking users.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The returned message states that '基础权限(消息收发等)已默认开启', implying the skill has enabled the bot's Feishu-side permissions. However, the implementation only creates the app via registration and writes credentials into openclaw.json; it does not call any API to grant or enable application permissions. This is an active contradiction between documentation/message text and actual behavior.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
This permission guide encourages enabling broad Feishu scopes across messages, documents, drive, calendar, tasks, wiki, and contacts, but it does not clearly explain the privacy, surveillance, and data-exposure consequences of granting those permissions. In the context of a one-click bot setup skill that creates a new app for users, omission of consent and least-privilege warnings can cause users to over-provision access without understanding that the bot may read sensitive enterprise content and personal data.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The success message returned by saveFeishuConfig is entirely in Chinese, which forces a specific language for users regardless of their preferences. This is a natural-language policy concern because the file does not offer localization, fallback text, or any opt-in for that locale.

Natural-Language Policy Violations

Low
Confidence
93% confidence
Finding
This markdown file presents all troubleshooting guidance exclusively in Chinese, with no indication that the skill or documentation is intentionally limited to Chinese-speaking users. Under the policy, forcing a specific language without user opt-in can be a natural-language policy violation.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
quick-setup.js:218

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
quick-setup.mjs:220