Back to skill

Security audit

Feishu Whiteboard

Security checks for vulnerabilities and agentic risk

Overview

This Feishu whiteboard skill has a coherent core purpose, but needs Review because it stores bearer tokens in a shared plaintext cache and ships runnable scripts that can mutate hard-coded Feishu boards and Wiki resources.

Review before installing. Only use this skill with least-privilege Feishu app credentials, remove or disable the hard-coded development scripts, avoid shared plaintext token caching, and document or separate any Wiki operations before granting broader scopes.

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
api.js:5
Finding

Tenant Access Token Stored in an Unprotected Shared Plaintext Cache

Content
View full analysis
now) { tokenCache.token = saved.token; tokenCache.expireTime = expiry; } } catch (e) { // Ignore corrupted cache } } ``` ```javascript tokenCache.token = data.tenant_access_token; tokenCache.expireTime = now + data.expire - 60; try { const cacheDir = path.dirname(TOKEN_CACHE_FILE); if (!fs.existsSync(cacheDir)) { fs.mkdirSync(cacheDir, { recursive: true }); } fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify({ token: tokenCache.token, expire: tokenCache.expireTime }, null, 2)); } catch (e) { console.error("Failed to save token cache:", e.message); } ``` ### Technical Analysis The Skill writes a Feishu tenant access token to `../../memory/feishu_token.json` as plaintext. The comment states that this cache is shared with other Feishu Skills. The file is created without an explicit restrictive mode, ownership checks, symlink checks, or an atomic file-creation strategy. A tenant access token is a bearer credential. Any process able to read it can submit authenticated Feishu API requests with the permissions granted to the associated application. Sharing the cache across components also increases the trust boundary: compromise or misbehavior in another local Skill may expose or replace the token. ...[truncated 1508 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
create_wiki_board.js:3
Finding

Undocumented Wiki and Whiteboard Read Operations Exceed the Declared Capability Scope

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
relocate.js:18
Finding

Immediately Executed Development Scripts Mutate Hard-Coded Feishu Resources

Content
View full analysis
Move to (1250, 7800) // Cloud: o2:41 (2250, 8500) -> Move to (1550, 7800) // Badge: o2:42 (2500, 8500) -> Move to (1850, 7800) // Arrows need to be deleted/redrawn or moved. Connectors usually auto-update if linked by ID, but mine were coord-based. // If they were coord-based, moving the shapes won't move the arrows' endpoints if they aren't bound. // My previous script used coordinate connectors. So I need to delete the old arrows and draw new ones, or just leave them as debris for now and focus on showing the nodes. // Let's just move the shapes first so he can SEE them. await updateNode(boardId, "o2:40", 1250, 7800); await updateNode(boardId, "o2:41", 1550, 7800); await updateNode(boardId, "o2:42", 1850, 7800); } main(); ``` The called mutation function is: ```javascript async function updateNode(boardId, nodeId, x, y) { try { console.log(`Moving node ${nodeId} to (${x}, ${y})...`); const res = await apiRequest('PUT', `/open-apis/board/v1/whiteboards/${boardId}/nodes/${nodeId}`, { node: { x: x, y: y } }); console.log(`Moved ${nodeId}: Success`); } catch (e) { console.error(`Failed to move ${nodeId}:`, e.message); } } ``` ### Technical Analysis ...[truncated 2020 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (15)

Memory Manipulation

High
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

Scanner excerpt · api.js (reported line 48)May include surrounding context.

js
}
  }

  // Force Refresh: Delete memory cache and file cache
  if (forceRefresh) {
    tokenCache.token = null;
    tokenCache.expireTime = 0;

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The markdown file instructs users to provide FEISHU_APP_ID and FEISHU_APP_SECRET but does not warn that these are sensitive credentials that should be protected and not committed or shared. For a skill that depends on secrets, the description should disclose the sensitivity and safe handling expectations.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

No manifest is available, so the skill has no stated purpose that would justify handling application secrets and maintaining a cross-skill token cache. The code loads FEISHU_APP_ID/FEISHU_APP_SECRET from environment/config and writes a shared bearer token to disk for reuse by other skills, which is a broader capability than a purpose-unknown helper can justify on its face.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · api.js (reported line 63)May include surrounding context.

js
throw new Error("Missing app_id or app_secret.");
  }

  const response = await fetch('https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

With no manifest or declared purpose, outbound requests to Feishu authentication and arbitrary Feishu API endpoints are unjustified by any stated intent. The module is effectively a general authenticated network client, which is a significant capability absent supporting documentation of scope.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The code sends app_id and app_secret to the Feishu token endpoint, which is a network operation involving sensitive credentials. While the behavior is functional, there is no confirmation prompt, user-facing log, or explanatory comment/docstring warning that credentials will be transmitted off-host.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The code persists a bearer access token in plaintext to a shared disk path under ../../memory/feishu_token.json, increasing the chance that another local process, skill, or user can read and reuse it. Because this is a shared cache location and there are no permission controls, encryption, or isolation measures, token theft could enable unauthorized Feishu API access until expiration.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script performs a real write operation to an externally hosted board using a hard-coded board ID, with no user confirmation, access validation, or contextual justification in the skill. In an agent skill context, silent modification of a remote collaborative resource is risky because it can alter someone else's data, trigger unintended side effects, or be repurposed for unauthorized changes if executed automatically.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

A hard-coded board identifier targets a specific remote resource without any runtime disclosure or user selection, which creates a direct path for unintended or unauthorized modification. In a skill setting, embedding a concrete external destination is especially dangerous because the action is pre-wired to affect a real board if the code runs with valid credentials.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This code embeds multiple user-visible flow labels in Chinese, such as activation, trust-code entry, and upload steps, while other labels remain in English. That creates a language/locale policy concern because the skill appears to force a specific language for core user interactions without opt-in or justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The diagram text shown to users is primarily in Chinese across multiple labels, with no indication that the skill is intended only for a Chinese-speaking audience or that another language is available. This creates a natural-language policy concern because the skill imposes a specific language without user opt-in.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The code transmits a wiki token in a network request by placing it directly into the URL query string. Tokens in URLs are commonly exposed through logs, proxies, browser/history tooling, monitoring systems, and error telemetry, which increases the chance of credential disclosure beyond the intended recipient.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The code reads FEISHU_APP_ID and FEISHU_APP_SECRET from environment variables, which are sensitive credentials. In this file there is no user-facing disclosure, docstring, or comment explaining that credential material will be accessed and used.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
71% confidence
Finding

The comment frames the connector choice as a safer approach, but the meaningful behavior of the code remains a write operation to an external board via addNodes. This documentation can mislead reviewers into thinking the operation is safety-limited when only the connector representation changed, not the side effects.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
93% confidence
Finding

The dependency version for dotenv uses a caret range (^16.0.0), which allows automatic installation of newer minor and patch releases. While this is common practice and not inherently malicious, it can introduce supply-chain risk if a future compatible release contains a vulnerability or malicious code, reducing build reproducibility and making deployments less predictable.

Content

Scanner excerpt · package.json (reported line 7)May include surrounding context.

json
"description": "Feishu Whiteboard Skill",
  "main": "create.js",
  "dependencies": {
    "dotenv": "^16.0.0"
  }
}