Back to skill

Security audit

Lark Toolkit

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent Lark integration guide, but it handles powerful workspace credentials and broad Lark permissions with weak scoping and an unsafe token helper.

Review and narrow Lark permissions before installing or using this skill. Prefer environment variables or a protected secret store over command-line secrets, avoid logging printed tokens, and do not run scripts/get_token.sh in environments where OPENCLAW_CONFIG can be influenced by untrusted input. Require explicit user confirmation before sending messages, sharing documents, adding members, or modifying calendars, tasks, Bitable records, OKRs, or other workspace data.

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)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/get_token.sh:23
Finding
Python Code Injection Through Unsafe Configuration Path Interpolation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/get_token.sh`, lines 23–42 **Vulnerability Type**: Environment-variable-driven Python code injection **Risk Level**: Medium ### Vulnerable Code ```bash CONFIG="${OPENCLAW_CONFIG:-$HOME/.openclaw/openclaw.json}" if [ -f "$CONFIG" ]; then echo "Reading credentials from $CONFIG (channels.lark.accounts.default)" >&2 APP_ID=$(python3 -c " import json, sys try: c = json.load(open('$CONFIG')) print(c['channels']['lark']['accounts']['default']['appId']) except (KeyError, FileNotFoundError): sys.exit(1) " 2>/dev/null) || true APP_SECRET=$(python3 -c " import json, sys try: c = json.load(open('$CONFIG')) print(c['channels']['lark']['accounts']['default']['appSecret']) except (KeyError, FileNotFoundError): sys.exit(1) " 2>/dev/null) || true fi ``` ### Technical Analysis The value of `OPENCLAW_CONFIG` is assigned to `CONFIG` and then interpolated directly into Python source passed to `python3 -c`. Although the shell variable is surrounded by single quotation marks in the generated Python expression, those quotation marks do not safely encode arbitrary path values. A configuration path containing a single quote and additional Python syntax can terminate the string passed to `open(...)` and inject attacker-controlled Python statements. The `[ -f "$CONFIG" ]` check limits exploitation to a value resolving to an existing file, but it does not make interpolation into executable Python source safe. On filesystems that permit quotation marks and other relevant characters in filenames, an attacker able to create a file and influence `OPENCLAW_CONFIG` can satisfy this condition. The vulnerable branch is reached when the caller does not provide both credentials through command-line arguments or environment variables. ### Attack Path 1. An attacker gains control over, or can influence, the `OPENCLAW_CONFIG` environment variable supplied to the helper. This could occur through a wrappe ...[truncated 1313 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Never interpolate a filesystem path into executable Python source. Pass the path as a positional argument: ```bash CREDENTIALS=$(python3 -c ' import json import sys with open(sys.argv[1], encoding="utf-8") as handle: config = json.load(handle) account = config["channels"]["lark"]["accounts"]["default"] print(account["appId"]) print(account["appSecret"]) ' "$CONFIG") ``` Additional hardening should include: 1. Parse both fields in one Python invocation to reduce complexity and duplicated attack surface. 2. Catch `json.JSONDecodeError`, `OSError`, `TypeError`, and `KeyError`, and return a clear error without exposing secrets. 3. Resolve and validate the configuration path where practical. 4. Reject configuration files that are writable by untrusted users. 5. Preserve shell quoting around `"$CONFIG"` whenever it is passed as an argument. 6. Add regression tests using paths containing quotes, spaces, newlines, backslashes, and shell metacharacters. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/get_token.sh:5
Finding
Lark Secrets and Bearer Tokens Exposed Through Command-Line and Standard Output Interfaces<![CDATA[ ## Vulnerability Details **File Location**: `scripts/get_token.sh`, lines 5–9, 19–20, and 64–65 **Vulnerability Type**: Sensitive credential and token exposure **Risk Level**: Low ### Vulnerable Code ```bash # Usage: # export LARK_APP_ID=cli_xxx LARK_APP_SECRET=xxx # source scripts/get_token.sh # # Credential sources (checked in order): # 1. Command-line arguments: ./get_token.sh <app_id> <app_secret> ``` ```bash APP_ID="${1:-${LARK_APP_ID:-}}" APP_SECRET="${2:-${LARK_APP_SECRET:-}}" ``` ```bash export LARK_TOKEN="$TOKEN" echo "$TOKEN" ``` ### Technical Analysis The helper explicitly accepts the long-lived Lark application secret as a command-line argument. Secrets provided this way may be exposed through: - Shell history. - Process inspection tools while the command is running. - CI/CD command logs. - Debugging or tracing output. - Audit records that capture command arguments. The helper also prints the resulting `tenant_access_token` to standard output unconditionally. This makes normal interactive or automated use liable to expose the bearer token in terminal capture, command logs, redirected files, or pipeline output. Exporting `LARK_TOKEN` is expected when the script is sourced and is necessary for its documented workflow. The security concern is the combination of an argument-based secret interface and unconditional plaintext token output. A tenant token inherits the Lark application permissions granted by the tenant administrator. ### Attack Path 1. A user follows the documented command-line interface and supplies the App ID and App Secret as arguments, or runs the helper in an environment that records command lines. 2. A local observer, process-monitoring service, shell-history reader, or CI log collector captures the App Secret. 3. Independently, the helper obtains a tenant token and writes it to standard output. 4. Terminal recording, build logging, output redirection, or a downstream pipeline captures the token. 5. An attack ...[truncated 990 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove support for passing `app_secret` as a command-line argument. 2. Prefer a protected configuration file, a secret manager, or a non-echoing interactive prompt. 3. If environment variables remain supported, document that they may still be visible to child processes and privileged local observers. 4. Do not print the bearer token by default when the script is sourced. 5. If machine-readable output is required, require an explicit option such as `--print-token` and display a warning that output must not be logged. 6. Separate operational modes: - A sourced mode that exports `LARK_TOKEN` without printing it. - A command mode that writes the token only when explicitly requested. 7. Ensure CI systems mask `LARK_APP_SECRET` and `LARK_TOKEN`. 8. Rotate the App Secret immediately if it appears in history or logs, and invalidate affected credentials where supported. 9. Avoid enabling shell tracing with `set -x` while handling these values. ]]>

T05 · Unauthorized Access and Privilege Escalation

Note
Location
references/bot-setup.md:13
Finding
Documented Minimum Permission Set Exceeds Mention-Only Bot Requirements<![CDATA[ ## Vulnerability Details **File Location**: `references/bot-setup.md`, lines 13–20 **Vulnerability Type**: Excessive Lark application permissions **Risk Level**: Low ### Vulnerable Code ```markdown ## 3. Permissions (Minimum Set) | Permission | Purpose | |-----------|---------| | `im:message` | Send & receive messages (DM + group) | | `im:message.p2p_msg:readonly` | Read user-to-bot DMs | | `im:message.group_msg:readonly` | Receive @bot messages in groups | | `im:message.group_at_msg:readonly` | Receive all group messages | | `im:chat` | Get/update group info | | `im:chat.members:write_only` | Manage group members (optional) | ``` ### Technical Analysis The guide labels this collection as the “Minimum Set,” but it includes permissions described as allowing the application to receive all group messages and to update group information. For a bot configured to respond only when mentioned, access to all group messages is broader than necessary. Similarly, a read/write chat permission is broader than a read-only permission when the bot only needs to inspect group information. The project later recommends `requireMention: true`, which indicates that mention-only behavior is an expected default. Granting broader API scopes despite that runtime policy violates least-privilege principles. Runtime mention filtering does not remove the underlying application permission or protect data if the token or bot implementation is compromised. The group-member management permission is marked optional, which is appropriate, but the other broad scopes are presented as part of the minimum baseline rather than feature-specific additions. ### Attack Path 1. A tenant administrator follows the setup guide and grants every permission listed under “Minimum Set.” 2. The Lark application receives a `tenant_access_token` inheriting all granted application permissions. 3. The token is exposed, the bot is compromised, or an authorized integration function is misused. 4. The a ...[truncated 954 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Replace the single “Minimum Set” with feature-specific permission profiles: 1. **Mention-only messaging baseline** - Grant only the scopes required to receive direct messages and messages that mention the bot. - Use a dedicated send-as-bot scope where supported instead of a broader combined scope. 2. **Group metadata** - Prefer `im:chat:readonly` when modification is not required. 3. **All-group-message processing** - Mark the permission to receive all group messages as optional and privacy-sensitive. - Explain the business requirement and obtain explicit tenant approval before enabling it. 4. **Membership management** - Keep `im:chat.members:write_only` optional and grant it only when member management is an enabled feature. 5. **Advanced modules** - Grant calendar, document, Bitable, task, Wiki, contact, and OKR scopes independently and only when those capabilities are used. 6. Restrict application availability to the smallest necessary set of users, groups, or departments. 7. Periodically review and remove unused permissions, then publish a new application version so reductions take effect. 8. Document that `requireMention: true` is only an application behavior control and is not a substitute for reducing API permissions. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
Findings (22)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The supplied code chunk is narrowly focused on obtaining a Lark tenant access token from the Lark International Open API using provided or locally stored credentials. It also reads from a local OpenClaw config file for fallback credentials. While this is plausibly a supporting utility for a larger Lark skill, the declared description presents the skill as a comprehensive API integration covering many categories of Lark/Feishu functionality and multiple access mechanisms. In this chunk, none of those operational capabilities are implemented; only authentication is. This is a material description-versus-behavior mismatch for the provided code chunk, even though token retrieval is related to the broader Lark domain.

External Script Fetching

High
Category
Supply Chain
Content
## Authentication (Direct API)

```bash
TOKEN=$(curl -s -X POST 'https://open.larksuite.com/open-apis/auth/v3/tenant_access_token/internal' \
  -H 'Content-Type: application/json' \
  -d '{"app_id":"<APP_ID>","app_secret":"<APP_SECRET>"}' \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['tenant_access_token'])")
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
GET /im/v1/messages/{message_id}/reactions

# Delete
DELETE /im/v1/messages/{message_id}/reactions/{reaction_id}
```

Valid emoji types: `THUMBSUP` `HEART` `LAUGH` `OK` `COOL` `FINGERHEART` `SMILE` `JIAYOU` `Get` `Salute` `Fireworks`
Confidence
80% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Credential Access

High
Category
Privilege Escalation
Content
mcporter call lark-mcp.<tool_name> key=value
```

All tools accept optional `useUAT=true` to use user access token instead of tenant token.

## Bitable (6 tools)
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

External Script Fetching

High
Category
Supply Chain
Content
fi

# Request tenant_access_token from Lark Open API
RESPONSE=$(curl -s https://open.larksuite.com/open-apis/auth/v3/tenant_access_token/internal \
  -H "Content-Type: application/json" \
  -d "{\"app_id\":\"$APP_ID\",\"app_secret\":\"$APP_SECRET\"}")
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The security section makes a misleading assurance about credential handling while also documenting fallback reads from ~/.openclaw/openclaw.json. In security-sensitive tooling, contradictory statements can cause operators to underestimate where secrets are sourced from, weakening review and increasing the chance of unintentional secret exposure or misuse.

External Transmission

Medium
Category
Data Exfiltration
Content
## Authentication (Direct API)

```bash
TOKEN=$(curl -s -X POST 'https://open.larksuite.com/open-apis/auth/v3/tenant_access_token/internal' \
  -H 'Content-Type: application/json' \
  -d '{"app_id":"<APP_ID>","app_secret":"<APP_SECRET>"}' \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['tenant_access_token'])")
Confidence
60% 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
### Send a Message

```bash
curl -X POST "https://open.larksuite.com/open-apis/im/v1/messages?receive_id_type=chat_id" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"receive_id":"CHAT_ID","msg_type":"text","content":"{\"text\":\"hello\"}"}'
```
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Session Persistence

Medium
Category
Rogue Agent
Content
| `im:chat.members:write_only` | Manage group members (optional) |

For advanced features, add:
- `calendar:calendar` — Calendar read/write
- `docs:doc` — Docs access
- `bitable:app` — Bitable access
- `task:task` — Task management
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The playbook explicitly shows placing `appId` and `appSecret` in a local config file under the user's home directory without any guidance on file permissions, secret managers, redaction, or avoiding source control. That creates a real secret-handling weakness because developers may persist long-lived bot credentials in plaintext where they can be exposed through backups, logs, shared machines, or accidental commits.

External Transmission

Medium
Category
Data Exfiltration
Content
## 8. Add Bot to Groups

```bash
curl -X POST "https://open.larksuite.com/open-apis/im/v1/chats/{chat_id}/members?member_id_type=app_id" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"id_list":["cli_bot_app_id"]}'
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
93% confidence
Finding
The file documents several state-changing and data-accessing MCP tools such as creating bitable apps, tables, records, and updating records, but provides no safety guidance about destructive effects, authorization scope, or confirmation requirements. In an agent skill context, this increases the chance an agent will perform writes to external business systems or expose organizational data without the user understanding the consequences.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The calendar, docs, messaging, and contact lookup sections describe operations that can send messages, create events, share documents, inspect message history, and resolve identities, yet the documentation includes no privacy, consent, or external-side-effect warnings. In a multi-tool agent environment, omission of these warnings can lead to unintended outbound communications, over-sharing, or privacy violations using legitimate platform capabilities.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
This markdown file documents permissions that allow sending messages, reading direct and group messages, accessing files, and managing group members, but it does not include any user-facing warning about the privacy and security impact of granting these capabilities. Under the markdown-specific SQP-2 criteria, descriptions of behaviors affecting user data or system integrity should disclose such risks.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
These permissions explicitly allow access to personally identifiable information, but the markdown provides only capability descriptions and no caution about privacy, consent, or least-privilege handling of that data. This is a missing user warning for behavior that could affect user privacy.

Missing User Warnings

Medium
Confidence
81% confidence
Finding
The file lists permissions that can read or modify calendars, documents, drive files, wiki content, tasks, and OKR progress, but it does not warn that granting write scopes can alter or overwrite organizational data. For markdown files, omission of warnings about data-impacting behavior is reportable under SQP-2.

Session Persistence

Medium
Category
Rogue Agent
Content
- claw-lark auto-restart bug (monitorLarkProvider resolves immediately in webhook mode)

**Fix:**
1. Kill competing process: `kill PID && launchctl unload ~/Library/LaunchAgents/com.xxx.plist`
2. Apply the pending-promise fix in `monitor.js` (see [webhook-setup.md](webhook-setup.md))
3. Restart gateway: `openclaw gateway restart`
Confidence
75% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

External Transmission

Medium
Category
Data Exfiltration
Content
**Fix:** Re-fetch `tenant_access_token`. Cache for no more than 1.5 hours (actual validity ~2h, but buffer for safety):
```bash
curl -s https://open.larksuite.com/open-apis/auth/v3/tenant_access_token/internal \
  -H "Content-Type: application/json" \
  -d '{"app_id":"$APP_ID","app_secret":"$APP_SECRET"}'
```
Confidence
60% 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
curl -s http://127.0.0.1:4040/api/tunnels | jq '.tunnels[] | {name, public_url, config}'

# Test webhook endpoint
curl -X POST http://127.0.0.1:3003/ -d '{"type":"url_verification","challenge":"test"}' -H "Content-Type: application/json"
# Should return: {"challenge":"test"}
```
Confidence
60% 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
fi

# Request tenant_access_token from Lark Open API
RESPONSE=$(curl -s https://open.larksuite.com/open-apis/auth/v3/tenant_access_token/internal \
  -H "Content-Type: application/json" \
  -d "{\"app_id\":\"$APP_ID\",\"app_secret\":\"$APP_SECRET\"}")
Confidence
70% 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

Low
Confidence
89% confidence
Finding
This markdown file shows how to request a tenant access token using `app_id` and `app_secret`, which are sensitive credentials. The reference does not include any warning not to expose, log, or commit these values, even though markdown files should warn about behaviors affecting privacy or system integrity.

Static analysis

No suspicious patterns detected.