Back to skill

Security audit

Feishu Sheet

Security checks for vulnerabilities and agentic risk

Overview

The skill appears intended to manage Feishu spreadsheets, but it includes unsafe image handling, unrestricted URL fetching, and destructive spreadsheet commands that need review before use.

Review this skill before installing. Use only a minimal-permission Feishu app, avoid float_image_url unless URL fetching is sandboxed or allowlisted, do not pass untrusted image paths, and require explicit confirmation before delete or overwrite operations. The token cache should be hardened before use on shared systems.

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

Error
Location
scripts/feishu-sheet.sh:223
Finding
Arbitrary Python Code Execution Through Unsafely Interpolated Image Path<![CDATA[ ## Vulnerability Details **File Location**: `scripts/feishu-sheet.sh`, lines 223–226 **Vulnerability Type**: Python code injection **Risk Level**: High ### Vulnerable Code ```bash image_array=$(python3 -c " with open('$image_path','rb') as f: print(list(f.read())) ") ``` ### Technical Analysis The user-controlled `image_path` argument is directly interpolated into source code passed to `python3 -c`. Shell quoting does not make this safe because the value is inserted inside a Python single-quoted string. A path containing a single quote followed by valid Python syntax can terminate the intended string and inject additional Python statements. The injected code runs with the same operating-system identity and permissions as the Skill process. This also contradicts the security statement in `SKILL.md` claiming that inline Python uses safe single-quoted strings. Single quotes alone do not prevent injection when untrusted values are concatenated into source code. ### Attack Path 1. An attacker influences the file path supplied to the `insert_image` action. 2. The attacker constructs a path containing a single quote and Python syntax that escapes the `open('$image_path', ...)` expression. 3. The shell expands `image_path` while constructing the `python3 -c` program. 4. Python parses and executes the injected statements. 5. The injected code can invoke system commands, read local files, or access credentials available to the Skill process. A vulnerable invocation has the following data flow: ```text insert_image argument -> image_path -> interpolation into python3 -c source -> arbitrary Python execution -> local process compromise ``` ### Impact Assessment Successful exploitation provides arbitrary code execution under the account running the Skill. The attacker may: - Read `~/.openclaw/openclaw.json` and recover configured credentials. - Read or modify other files accessible to the process. - Access the cached Feishu tenant token. - I ...[truncated 361 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Never insert file paths or other untrusted values into generated Python source. Pass the path as a positional argument: ```bash image_array=$(python3 -c ' import sys with open(sys.argv[1], "rb") as f: print(list(f.read())) ' "$image_path") ``` Additionally: 1. Validate that the path refers to an allowed regular file. 2. Reject symbolic links if they are not required. 3. Apply file-size limits before reading the entire image into memory. 4. Validate the file's actual image type rather than relying on its name. 5. Pass all dynamic values to Python through `sys.argv`, standard input, or structured JSON. 6. Add regression tests using paths containing quotes, backslashes, newlines, and Python syntax. 7. Correct the security documentation so it reflects the implementation and does not claim unsafe interpolation is protected. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/feishu-sheet.sh:282
Finding
Unrestricted URL Retrieval Enables SSRF and Local File Exfiltration<![CDATA[ ## Vulnerability Details **File Location**: `scripts/feishu-sheet.sh`, lines 282–301 **Vulnerability Type**: Server-side request forgery and arbitrary resource retrieval **Risk Level**: High ### Vulnerable Code ```bash action_float_image_url() { local token="$1" sheet_id="$2" image_url="$3" range="${4:-${sheet_id}!A1:A1}" local width="${5:-400}" height="${6:-300}" local tmpfile tmpfile=$(mktemp /tmp/feishu_img_XXXXXX) local filename filename=$(basename "$image_url" | sed 's/\?.*//') [[ "$filename" != *.* ]] && filename="${filename}.png" curl -sL "$image_url" -o "$tmpfile" if [[ ! -s "$tmpfile" ]]; then rm -f "$tmpfile" echo '{"error":"Failed to download image from URL"}' return 1 fi action_float_image "$token" "$sheet_id" "$tmpfile" "$range" "$width" "$height" rm -f "$tmpfile" } ``` ### Technical Analysis The `float_image_url` action gives an attacker control over the URL passed to `curl`. The implementation does not restrict: - URL schemes. - Destination hosts or IP addresses. - Loopback, private, link-local, or cloud metadata addresses. - Redirect destinations. - Response size. - MIME type or actual file format. - Download duration. The `-L` option follows redirects without revalidating each destination. Depending on the protocols enabled in the installed curl build, non-HTTP schemes such as `file://` may also be accepted. The retrieved bytes are subsequently passed to `action_float_image` and uploaded to Feishu. The behavior exceeds the declared network scope in `SKILL.md`, which states that network access is limited to `open.feishu.cn`. Retrieving a user-selected remote image may be part of the declared feature, but unrestricted access to local files and internal network services is not necessary. ### Attack Path 1. An attacker invokes or causes the agent to invoke `float_image_url`. 2. The attacker supplies one of the following: - A URL targeting a loopback service. - A URL targeting a private ...[truncated 1299 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Implement strict URL and response validation before downloading: 1. Permit only `https://` URLs: ```bash curl --proto '=https' --proto-redir '=https' ... ``` 2. Parse the URL with a dedicated parser and reject embedded credentials, malformed hosts, and unexpected ports. 3. Resolve the hostname and reject loopback, private, link-local, multicast, reserved, and unspecified IPv4 and IPv6 addresses. 4. Revalidate the destination after every redirect or disable redirects entirely. 5. Consider an explicit hostname allowlist if arbitrary external images are not essential. 6. Apply connection, overall-duration, and maximum-file-size limits. 7. Validate the response `Content-Type` and inspect the downloaded bytes to confirm a supported image format. 8. Run downloads in a network-restricted sandbox that cannot reach local or private services. 9. Ensure temporary files are removed using a shell `trap`, including on errors and interruption. 10. Update `SKILL.md` to accurately disclose any required external image-host access. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/feishu-sheet.sh:64
Finding
Feishu Bearer Token Cached at a Predictable Path Without Enforced Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/feishu-sheet.sh`, lines 17–18 and 64–85 **Vulnerability Type**: Insecure sensitive-token storage and unsafe temporary-file handling **Risk Level**: Medium ### Vulnerable Code ```bash TOKEN_CACHE="${TMPDIR:-/tmp}/.feishu_tenant_token_$(id -u)" TOKEN_EXPIRE="${TMPDIR:-/tmp}/.feishu_tenant_token_expire_$(id -u)" ``` ```bash get_tenant_token() { local now now=$(date +%s) if [[ -f "$TOKEN_CACHE" && -f "$TOKEN_EXPIRE" ]]; then local expire expire=$(cat "$TOKEN_EXPIRE") if (( now < expire )); then cat "$TOKEN_CACHE" return fi fi local resp resp=$(curl -s -X POST "$FEISHU_BASE/auth/v3/tenant_access_token/internal" \ -H "Content-Type: application/json" \ -d "{\"app_id\":\"$FEISHU_APP_ID\",\"app_secret\":\"$FEISHU_APP_SECRET\"}") local token token=$(echo "$resp" | python3 -c "import sys,json; print(json.load(sys.stdin).get('tenant_access_token',''))" 2>/dev/null) local expire_in expire_in=$(echo "$resp" | python3 -c "import sys,json; print(json.load(sys.stdin).get('expire',7200))" 2>/dev/null) if [[ -z "$token" ]]; then echo "{\"error\":\"Failed to get tenant_access_token\"}" >&2 exit 1 fi echo "$token" > "$TOKEN_CACHE" echo $(( now + expire_in - 300 )) > "$TOKEN_EXPIRE" echo "$token" } ``` ### Technical Analysis The tenant access token is written to a predictable path derived only from `TMPDIR` and the numeric user ID. The script does not: - Set a restrictive `umask`. - Explicitly create the cache with mode `0600`. - Verify that the cache is owned by the current user. - Verify that the destination is a regular file rather than a symbolic link. - Create and replace cache contents atomically. - Ensure that `TMPDIR` itself is private and trustworthy. The final file permissions therefore depend on the caller's environment and umask. In a shared or attacker-controlled temporary directory, this can expose the bearer token or permit fil ...[truncated 1549 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Store the token in a private, per-user runtime directory with enforced permissions: ```bash umask 077 cache_dir="${XDG_RUNTIME_DIR:-$HOME/.cache}/feishu-sheet" mkdir -p -- "$cache_dir" chmod 700 -- "$cache_dir" TOKEN_CACHE="$cache_dir/tenant_token" TOKEN_EXPIRE="$cache_dir/tenant_token_expire" ``` Further hardening should include: 1. Reject an untrusted `TMPDIR`, or avoid it for credential storage. 2. Verify that the cache directory and files are owned by the effective user. 3. Reject symbolic links and non-regular files. 4. Create temporary cache files with `mktemp` inside the private directory. 5. Write with mode `0600`, then atomically rename the completed file. 6. Use file locking to avoid races between concurrent processes. 7. Delete expired token material promptly. 8. Prefer an operating-system credential store or avoid persistent token caching if performance permits. 9. Minimize Feishu application permissions so token compromise has the smallest possible impact. ]]>
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 (17)

Credential Access

High
Category
Privilege Escalation
Content
credentialPath: "channels.feishu"
    networkAccess: "open.feishu.cn (Feishu Open API only)"
    fileAccess: "Reads local image files only when explicitly passed to insert_image/float_image commands"
    tokenCache: "Tenant access token cached in $TMPDIR with per-user isolation (uid suffix)"
    note: "Credentials are validated against ^[A-Za-z0-9_-]+$ before use. Python inline script uses single-quoted strings to prevent shell injection. Recommend using a minimal-permission Feishu app."
---
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
  fi
  local resp
  resp=$(curl -s -X POST "$FEISHU_BASE/auth/v3/tenant_access_token/internal" \
    -H "Content-Type: application/json" \
    -d "{\"app_id\":\"$FEISHU_APP_ID\",\"app_secret\":\"$FEISHU_APP_SECRET\"}")
  local token
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Scope Creep

High
Confidence
98% confidence
Finding
The script uses Feishu Drive media upload APIs (`/drive/v1/medias/upload_all`) to implement floating-image support, but the skill metadata only declares `sheets:spreadsheet` permission scope. This is a real capability mismatch that can lead to over-privileged app configuration and broader-than-advertised access to Feishu resources.

External Script Fetching

High
Category
Supply Chain
Content
filename=$(basename "$image_url" | sed 's/\?.*//')
  [[ "$filename" != *.* ]] && filename="${filename}.png"

  curl -sL "$image_url" -o "$tmpfile"
  if [[ ! -s "$tmpfile" ]]; then
    rm -f "$tmpfile"
    echo '{"error":"Failed to download image from URL"}'
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
action_delete_rows() {
  local body="{\"dimension\":{\"sheetId\":\"$2\",\"majorDimension\":\"ROWS\",\"startIndex\":$3,\"endIndex\":$4}}"
  api_call DELETE "/sheets/v2/spreadsheets/$1/dimension_range" -d "$body" | python3 -c "
import sys,json
d = json.load(sys.stdin)
print(json.dumps({'success':d.get('code',1)==0,'msg':d.get('msg','')}, ensure_ascii=False, indent=2))
Confidence
90% 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).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
action_delete_rows() {
  local body="{\"dimension\":{\"sheetId\":\"$2\",\"majorDimension\":\"ROWS\",\"startIndex\":$3,\"endIndex\":$4}}"
  api_call DELETE "/sheets/v2/spreadsheets/$1/dimension_range" -d "$body" | python3 -c "
import sys,json
d = json.load(sys.stdin)
print(json.dumps({'success':d.get('code',1)==0,'msg':d.get('msg','')}, ensure_ascii=False, indent=2))
Confidence
90% 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).

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill explicitly instructs use of `exec` to run a shell script and documents network access to Feishu APIs, but it does not declare a restrictive tool scope such as `permissions` or `allowed-tools`. In an agent environment, this weakens enforcement boundaries and can let a broadly capable skill invoke shell and network operations without clear least-privilege constraints.

Session Persistence

Medium
Category
Rogue Agent
Content
### 创建电子表格
```bash
exec command="~/.openclaw/skills/feishu-sheet/scripts/feishu-sheet.sh create '表格标题'"
```
返回 `spreadsheet_token` 和 URL。可选第二参数 `folder_token`。
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.

Session Persistence

Medium
Category
Rogue Agent
Content
### 创建电子表格
```bash
exec command="~/.openclaw/skills/feishu-sheet/scripts/feishu-sheet.sh create '表格标题'"
```
返回 `spreadsheet_token` 和 URL。可选第二参数 `folder_token`。
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
89% confidence
Finding
The documentation exposes destructive operations such as `delete_sheet`, `delete_rows`, and `delete_cols` without any warning, confirmation requirement, or guidance about irreversibility. In agent-driven workflows, this increases the chance of accidental or unauthorized data destruction, especially if a user prompt is ambiguous.

External Transmission

Medium
Category
Data Exfiltration
Content
fi
  fi
  local resp
  resp=$(curl -s -X POST "$FEISHU_BASE/auth/v3/tenant_access_token/internal" \
    -H "Content-Type: application/json" \
    -d "{\"app_id\":\"$FEISHU_APP_ID\",\"app_secret\":\"$FEISHU_APP_SECRET\"}")
  local token
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

Medium
Confidence
91% confidence
Finding
The tenant access token is cached in predictable files under `/tmp` without explicit permission hardening or secure storage controls. On multi-user or weakly isolated systems, another local process may read or race these files, allowing unauthorized reuse of Feishu API credentials.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The skill exposes a `float_image_url` action that fetches arbitrary user-supplied URLs, which expands behavior beyond the declared Feishu Sheets-only scope into general outbound network access. This creates SSRF-like risk, unexpected data transfer, and policy/scope mismatch because the tool can be used to contact untrusted hosts and then relay that content into Feishu.

External Transmission

Medium
Category
Data Exfiltration
Content
filename=$(basename "$image_url" | sed 's/\?.*//')
  [[ "$filename" != *.* ]] && filename="${filename}.png"

  curl -sL "$image_url" -o "$tmpfile"
  if [[ ! -s "$tmpfile" ]]; then
    rm -f "$tmpfile"
    echo '{"error":"Failed to download image from URL"}'
Confidence
95% confidence
Finding
This network call downloads arbitrary external content from a user-controlled URL, which is outside the core Sheets API behavior and can be abused for SSRF-like access or unreviewed content transfer. In the context of an agent skill, giving the tool arbitrary fetch capability materially increases risk compared with normal Feishu API communication.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The script silently downloads remote content to a local temp file and then uploads it to Feishu, causing cross-boundary data transfer the user may not expect. This is risky because a crafted URL can make the tool retrieve attacker-chosen content and move it into the user's Feishu environment without meaningful warning or review.

Natural-Language Policy Violations

Low
Confidence
97% confidence
Finding
The create action defaults the spreadsheet title to '新建电子表格', which imposes a specific language/locale in user-visible output. There is no opt-in, locale detection, or documented justification for forcing Chinese as the default.

Natural-Language Policy Violations

Low
Confidence
61% confidence
Finding
The script mixes English-only help text with a Chinese default spreadsheet title, creating inconsistent locale assumptions rather than offering a user-selected language. This can be considered a language policy issue because user-facing language is imposed without opt-in or documented regional scope.

Static analysis

No suspicious patterns detected.