Back to skill

Security audit

feishu-minutes

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it says, but it handles Feishu credentials and meeting tokens in ways users should review before installing.

Install only if you are comfortable with local storage of Feishu meeting transcripts, recordings, and a cached tenant access token. Run it in a private workspace, protect or clear the memory directory, avoid shared logs, and prefer tightly scoped Feishu app credentials.

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
index.js:30
Finding

Feishu Minutes Token Disclosure Through Process Logs

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
lib/auth.js:114
Finding

Tenant Access Token Stored in a Plaintext Cache File Without Explicitly Restricted Permissions

Content
View full analysis
now) { tokenCache.token = saved.token; tokenCache.expireTime = expiry; } ``` ### Technical Analysis After authenticating with Feishu, the Skill persists the tenant access token as unencrypted JSON. The `fs.writeFileSync` call does not specify a restrictive file mode. For a newly created file, Node.js therefore uses default creation permissions subject to the process umask. The resulting confidentiality depends on the deployment environment rather than an explicit security guarantee. If the file already exists, its existing permissions also remain relevant. The cache is stored at a predictable location under a shared `memory` directory and is described as shared with other Skills. This increases the number of local components that may interact with the same credential. Local processes, workspace artifact collectors, backups, or users with filesystem access could obtain an unexpired bearer token. Caching the token is a performance optimization rather than a minimum requirement for retrieving Feishu Minutes. If persistent caching is retained, it must be protected as credential storage. ### Attack Path 1. The Skill sends the configured application ID and secret to Feishu's official HTTPS authentication endpoint. 2. Feishu re ...[truncated 1155 chars]
Remediation
View remediation
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
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (13)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · lib/auth.js (reported line 4)May include surrounding context.

js
const fs = require('fs');
const path = require('path');

// Robust .env loading
const possibleEnvPaths = [
  path.resolve(process.cwd(), '.env'),
  path.resolve(__dirname, '../../../.env'),

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · lib/auth.js (reported line 6)May include surrounding context.

js
// Robust .env loading
const possibleEnvPaths = [
  path.resolve(process.cwd(), '.env'),
  path.resolve(__dirname, '../../../.env'),
  path.resolve(__dirname, '../../../../.env')
];

Credential Access

High
Category
Privilege Escalation
Confidence
74% confidence
Finding

The code searches parent directories for .env files, which can cause secrets to be loaded from unexpected locations outside the application's intended boundary. In shared or multi-project environments, this increases the risk of accidentally ingesting the wrong credentials or attacker-influenced configuration, leading to confused-deputy behavior or unauthorized external authentication attempts.

Content

Scanner excerpt · lib/auth.js (reported line 7)May include surrounding context.

js
// Robust .env loading
const possibleEnvPaths = [
  path.resolve(process.cwd(), '.env'),
  path.resolve(__dirname, '../../../.env'),
  path.resolve(__dirname, '../../../../.env')
];

Credential Access

High
Category
Privilege Escalation
Confidence
78% confidence
Finding

Searching even higher-level parent directories for .env files broadens the trust boundary further and makes configuration source ambiguity worse. If a higher-level .env is present or writable by another actor, the application may silently consume unintended secrets and then use them to request tokens from the external API.

Content

Scanner excerpt · lib/auth.js (reported line 8)May include surrounding context.

js
const possibleEnvPaths = [
  path.resolve(process.cwd(), '.env'),
  path.resolve(__dirname, '../../../.env'),
  path.resolve(__dirname, '../../../../.env')
];

let envLoaded = false;

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 · lib/auth.js (reported line 67)May include surrounding context.

js
}
  }

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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · lib/auth.js (reported line 135)May include surrounding context.

js
}
  }

  throw lastError || new Error("Failed to retrieve access token after retries");
}

module.exports = {

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill explicitly states it fetches transcripts and media and stores them as local files, but it does not warn that these artifacts may contain highly sensitive meeting content, personal data, or confidential business information. This omission can cause users to run the skill in insecure environments, unintentionally retain sensitive data on disk, or mishandle exported recordings and transcripts.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

This code reads sensitive credentials from environment variables and config files, then uses them to obtain an access token and persists that token to disk. While there is some error logging, there is no visible comment, prompt, or user-facing disclosure warning that credentials are being consumed and that authentication tokens will be stored in a local cache file.

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 · lib/auth.js (reported line 86)May include surrounding context.

js
let lastError;
  for (let attempt = 1; attempt <= 3; attempt++) {
    try {
      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({

Vague Triggers

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

This is a manifest file, so vague-trigger checks apply. The description states the skill can 'Fetch info, subtitle, and media from Feishu Minutes (Yi)' but provides no specific activation phrases, constraints, or exclusion conditions, making invocation scope ambiguous.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
77% confidence
Finding

Using a caret version for dotenv allows future compatible releases within the major version range to be installed, which can introduce unexpected supply-chain changes over time. While not immediately exploitable from this file alone, looser dependency pinning increases the chance of pulling a compromised or breaking upstream release in future installs.

Content

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

json
"test": "echo \"Error: no test specified\" && exit 1"
  },
  "dependencies": {
    "dotenv": "^16.3.1",
    "node-fetch": "^2.7.0",
    "yargs": "^17.7.2"
  }

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
77% confidence
Finding

Using a caret version for node-fetch permits automatic uptake of later minor or patch releases, which expands supply-chain exposure if an upstream package is compromised or introduces unsafe behavior. The risk is contextual and indirect, but exact pinning is a common hardening measure for reproducible and safer builds.

Content

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

json
},
  "dependencies": {
    "dotenv": "^16.3.1",
    "node-fetch": "^2.7.0",
    "yargs": "^17.7.2"
  }
}

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
77% confidence
Finding

Using a caret version for yargs means installations may resolve to different package contents over time, creating a supply-chain risk window if a later allowed release is malicious or flawed. This does not indicate active compromise here, but it is a real hardening weakness for dependency control.

Content

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

json
"dependencies": {
    "dotenv": "^16.3.1",
    "node-fetch": "^2.7.0",
    "yargs": "^17.7.2"
  }
}