Back to skill

Security audit

Feishu Meeting

Security checks for vulnerabilities and agentic risk

Overview

This Feishu meeting skill does what it says, but its shell script can turn meeting input into local Python code execution and uses broad calendar-writing authority.

Review before installing. Use only with a least-privilege Feishu app and an unprivileged runtime account, and do not pass untrusted meeting titles, recurrence rules, or start times until the script is fixed to pass data into Python via arguments or stdin. Add an explicit confirmation step before creating events or sending invitee phone/email data 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 (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/create.sh:69
Finding
Arbitrary Python Code Execution Through Unsafe Variable Interpolation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/create.sh`, lines 69–73, 82–95, and 146–151 **Vulnerability Type**: Python source-code injection **Risk Level**: High ### Vulnerable Code #### Start-time interpolation at lines 69–73 ```bash START_TS=$(date -d "$START_TIME" +%s 2>/dev/null || python3 -c " from datetime import datetime print(int(datetime.strptime('$START_TIME', '%Y-%m-%d %H:%M').timestamp())) ") ``` #### Meeting topic and recurrence-rule interpolation at lines 82–95 ```bash EVENT_JSON=$(python3 -c " import json event = { 'summary': '''$MEETING_TOPIC''', 'start_time': {'timestamp': '$START_TS', 'timezone': 'Asia/Shanghai'}, 'end_time': {'timestamp': '$END_TS', 'timezone': 'Asia/Shanghai'}, 'vchat': {'vc_type': 'vc'}, 'attendee_ability': 'can_see_others' } rrule = '''$RRULE''' if rrule: r = rrule.replace('RRULE:', '') if 'COUNT' not in r and 'UNTIL' not in r: r += ';COUNT=52' event['recurrence'] = r print(json.dumps(event, ensure_ascii=False)) ") ``` #### Owner and resolved identifier interpolation at lines 146–151 ```bash ATTENDEES_JSON=$(python3 -c " import json owner = '$DEFAULT_OWNER_OPEN_ID' extras = [x for x in '$EXTRA_OPEN_IDS'.split(',') if x] all_ids = list(dict.fromkeys([owner] + extras)) print(json.dumps({'attendees': [{'type':'user','user_id':uid} for uid in all_ids]})) ") ``` ### Technical Analysis The script constructs Python programs using `python3 -c` and directly inserts shell-variable contents into the Python source. These values are not encoded as Python string literals and are not passed through a structured interface such as command-line arguments or standard input. The following values reach generated Python source: - `START_TIME`, supplied through `--start` - `MEETING_TOPIC`, supplied as the first positional argument - `RRULE`, supplied through `--rrule` - `DEFAULT_OWNER_OPEN_ID`, obtained from configuration - `EXTRA_OPEN_IDS`, derived from the Feishu API res ...[truncated 2486 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Never interpolate variable contents into Python source code.** Pass every dynamic value as a positional argument: ```bash START_TS=$(python3 - "$START_TIME" <<'PY' from datetime import datetime import sys value = sys.argv[1] print(int(datetime.strptime(value, "%Y-%m-%d %H:%M").timestamp())) PY ) ``` 2. **Construct the event payload from command-line arguments or standard input:** ```bash EVENT_JSON=$(python3 - "$MEETING_TOPIC" "$START_TS" "$END_TS" "$RRULE" <<'PY' import json import sys topic, start_ts, end_ts, rrule = sys.argv[1:] event = { "summary": topic, "start_time": { "timestamp": start_ts, "timezone": "Asia/Shanghai", }, "end_time": { "timestamp": end_ts, "timezone": "Asia/Shanghai", }, "vchat": {"vc_type": "vc"}, "attendee_ability": "can_see_others", } if rrule: recurrence = rrule.removeprefix("RRULE:") if "COUNT" not in recurrence and "UNTIL" not in recurrence: recurrence += ";COUNT=52" event["recurrence"] = recurrence print(json.dumps(event, ensure_ascii=False)) PY ) ``` 3. **Construct attendee data using positional arguments rather than generated source:** ```bash ATTENDEES_JSON=$(python3 - "$DEFAULT_OWNER_OPEN_ID" "$EXTRA_OPEN_IDS" <<'PY' import json import sys owner = sys.argv[1] extras = [value for value in sys.argv[2].split(",") if value] all_ids = list(dict.fromkeys([owner, *extras])) print(json.dumps({ "attendees": [ {"type": "user", "user_id": user_id} for user_id in all_ids ] })) PY ) ``` 4. Validate all inputs before use: - Require `DURATION` to be a bounded positive integer. - Parse start times using one strict, documented format. - Validate RRULE fields against an allowlist of supported RFC 5545 components. - Apply reasonable maximum lengths to topics and invitee lists. - Validate Feishu Open IDs and calendar IDs against their expected formats. 5. Run the Skill as an unp ...[truncated 459 chars]
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (13)

External Script Fetching

High
Category
Supply Chain
Content
```bash
# After configuring Feishu appId/appSecret in openclaw.json:
curl -s "https://open.feishu.cn/open-apis/calendar/v4/calendars" \
  -H "Authorization: Bearer $TOKEN" | python3 -c "
import json,sys
for c in json.load(sys.stdin)['data']['calendar_list']:
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Credential Access

High
Category
Privilege Escalation
Content
APP_ID=$(python3 -c "import json; print(json.load(open('$CONFIG_FILE'))['channels']['feishu']['appId'])")
APP_SECRET=$(python3 -c "import json; print(json.load(open('$CONFIG_FILE'))['channels']['feishu']['appSecret'])")

# --- Get Tenant Access Token ---
ACCESS_TOKEN=$(curl -s -X POST \
  "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal" \
  -H "Content-Type: application/json" \
Confidence
73% confidence
Finding
The script directly accesses long-lived application credentials from a local file and uses them to mint a tenant access token without any guardrails around secret storage, permission checks, or execution context. In an agent-skill setting, this increases the blast radius if the skill is triggered in an untrusted or overly broad environment, because compromise of the host or misuse of the skill can leverage privileged API credentials.

External Script Fetching

High
Category
Supply Chain
Content
APP_SECRET=$(python3 -c "import json; print(json.load(open('$CONFIG_FILE'))['channels']['feishu']['appSecret'])")

# --- Get Tenant Access Token ---
ACCESS_TOKEN=$(curl -s -X POST \
  "https://open.feishu.cn/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.

External Script Fetching

High
Category
Supply Chain
Content
")

# --- Step 1: Create Calendar Event ---
CREATE_RESP=$(curl -s -X POST \
  "https://open.feishu.cn/open-apis/calendar/v4/calendars/${CALENDAR_ID}/events?user_id_type=open_id" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json; charset=utf-8" \
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
print(json.dumps({'attendees': [{'type':'user','user_id':uid} for uid in all_ids]}))
")

ATT_RESP=$(curl -s -X POST \
  "https://open.feishu.cn/open-apis/calendar/v4/calendars/${CALENDAR_ID}/events/${EVENT_ID}/attendees?user_id_type=open_id" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json; charset=utf-8" \
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
95% confidence
Finding
The skill advertises operational behavior that clearly requires network and shell access, but it does not declare any explicit tool scope or allowed-tools boundary. That weakens governance and review controls, making it easier for an agent runtime to grant broader capabilities than users or operators expect when the skill is invoked.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The activation phrases are broad enough to match ordinary meeting or scheduling requests, which can cause the skill to trigger in situations where the user did not specifically intend Feishu calendar writes or external API use. In context, that increases the chance of unintended meeting creation, attendee resolution, and data transmission to Feishu.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill describes meeting creation convenience but does not clearly disclose that invitee phone numbers/emails and event metadata will be sent to Feishu APIs and written into participants' calendars. This is a privacy and consent issue because users may provide third-party identifiers without realizing the external transmission and side effects.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
The script accesses sensitive credentials by reading appId and appSecret from the OpenClaw config file. Although the header comments describe the skill purpose, there is no explicit warning, prompt, or user-facing notice that local credentials will be accessed during execution.

External Transmission

Medium
Category
Data Exfiltration
Content
APP_SECRET=$(python3 -c "import json; print(json.load(open('$CONFIG_FILE'))['channels']['feishu']['appSecret'])")

# --- Get Tenant Access Token ---
ACCESS_TOKEN=$(curl -s -X POST \
  "https://open.feishu.cn/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.

External Transmission

Medium
Category
Data Exfiltration
Content
")

# --- Step 1: Create Calendar Event ---
CREATE_RESP=$(curl -s -X POST \
  "https://open.feishu.cn/open-apis/calendar/v4/calendars/${CALENDAR_ID}/events?user_id_type=open_id" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json; charset=utf-8" \
Confidence
70% 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
print(json.dumps({'attendees': [{'type':'user','user_id':uid} for uid in all_ids]}))
")

ATT_RESP=$(curl -s -X POST \
  "https://open.feishu.cn/open-apis/calendar/v4/calendars/${CALENDAR_ID}/events/${EVENT_ID}/attendees?user_id_type=open_id" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json; charset=utf-8" \
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The script emits all user-facing success and status messages in Chinese only. This is a natural-language policy concern because it imposes a specific language without offering opt-in, fallback, or locale selection.

Static analysis

No suspicious patterns detected.