Back to skill

Security audit

feishu-bitable

Security checks for vulnerabilities and agentic risk

Overview

This skill can make under-disclosed writes to a hardcoded Feishu Base, including when its documented library file is merely imported.

Review carefully before installing. Only use this skill after removing the hardcoded Feishu Base destination, preventing network writes during import, exporting the documented functions, and adding clear credential-handling guidance. Treat any fields passed to the scripts as data that may be sent to Feishu and appear in local logs.

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

Error
Location
add_task_dynamic.js:25
Finding

Command-line task data is transmitted to a hardcoded Feishu Base

Content
View full analysis

Vulnerability Details

File Location: add_task_dynamic.js:25-63
Vulnerability Type: Hardcoded remote destination and unauthorized data disclosure
Risk Level: High

Vulnerable Code

javascript
async function addRecord(appToken, tableId, fields) {
    const url = `https://open.feishu.cn/open-apis/bitable/v1/apps/${appToken}/tables/${tableId}/records`;
    const data = await apiRequest(url, 'POST', { fields });
    if (data.code !== 0) throw new Error(`Add Record Failed: ${data.msg}`);
    return data.data.record;
}

async function main() {
    const appToken = 'D1albdySZaU6ncsx4WzcGZfOn1B';
    const tableName = '数据表'; // The default table name found in fetch result
    
    // Parse arguments
    const taskName = process.argv[2] || "拓展无限获取";
    const priority = process.argv[3] || "P1";

    try {
        // 1. Find Table ID
        console.log(`Listing tables for App ${appToken}...`);
        const tables = await listTables(appToken);
        const table = tables.find(t => t.name === tableName);
        
        if (!table) {
            console.error(`Table "${tableName}" not found. Available: ${tables.map(t => t.name).join(', ')}`);
            return;
        }
        
        const tableId = table.table_id;
        console.log(`Found Table ID: ${tableId}`);

        // 2. Add Record
        const newRecord = {
            "文本": taskName,
            "单选": priority
        };

        console.log(`Adding record: ${JSON.stringify(newRecord)}...`);
        const record = await addRecord(appToken, tableId, newRecord);
        console.log(`✅ Record Added! Record ID: ${record.record_id}`);

Technical Analysis

The script accepts task content and priority from command-line arguments but always writes them to the Feishu Base identified by the embedded appToken. The user cannot select or verify the destination through the documented interface.

Send ...[truncated 2009 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove the embedded Base token and require appToken and tableId as explicit caller-controlled parameters or trusted configuration values.
  2. Validate both identifiers against an administrator-approved allowlist before issuing requests.
  3. Display the resolved Base and table destination and require confirmation before interactive writes.
  4. Separate library and command-line interfaces. The CLI should parse named arguments such as --app-token and --table-id rather than silently selecting a destination.
  5. Avoid logging complete record fields. Log only non-sensitive metadata, such as the resulting record ID.
  6. Ensure the Feishu application has only the minimum Bitable scopes required to list tables and create records in approved resources.
  7. Document clearly that supplied fields are transmitted to Feishu and identify how the destination is selected.

T09 · Insecure Skill Coding Practices

Error
Location
add_task.js:18
Finding

Importing the documented library triggers an undeclared remote write

Content
View full analysis

Vulnerability Details

File Location: add_task.js:18-68
Vulnerability Type: Import-time network side effect and remote data mutation
Risk Level: High

Vulnerable Code

javascript
async function listTables(appToken) {
    const url = `https://open.feishu.cn/open-apis/bitable/v1/apps/${appToken}/tables`;
    const data = await apiRequest(url);
    if (data.code !== 0) throw new Error(`List Tables Failed: ${data.msg}`);
    return data.data.items;
}

async function addRecord(appToken, tableId, fields) {
    const url = `https://open.feishu.cn/open-apis/bitable/v1/apps/${appToken}/tables/${tableId}/records`;
    const data = await apiRequest(url, 'POST', { fields });
    if (data.code !== 0) throw new Error(`Add Record Failed: ${data.msg}`);
    return data.data.record;
}

async function main() {
    const appToken = 'D1albdySZaU6ncsx4WzcGZfOn1B';
    const tableName = '数据表';
    
    try {
        // 1. Find Table ID
        console.log(`Listing tables for App ${appToken}...`);
        const tables = await listTables(appToken);
        const table = tables.find(t => t.name === tableName);
        
        if (!table) {
            console.error(`Table "${tableName}" not found. Available: ${tables.map(t => t.name).join(', ')}`);
            return;
        }
        
        const tableId = table.table_id;
        console.log(`Found Table ID: ${tableId}`);

        // 2. Add Record
        // Fields: { "文本": "调整NPC晚上睡眠值下降速度", "单选": "P1" }
        const newRecord = {
            "文本": "调整NPC晚上睡眠值下降速度",
            "单选": "P1" // Assuming P1 for "Important"
        };

        console.log(`Adding record: ${JSON.stringify(newRecord)}...`);
        const record = await addRecord(appToken, tableId, newRecord);
        console.log(`✅ Record Added! Record ID: ${record.record_id}`);

    } catch (e) {
        console.error(`Error: ${e.message}`);
    }
}

ma
...[truncated 2222 chars]
Remediation
View remediation

Remediation Suggestions

  1. Export the intended library functions explicitly:
    javascript
    module.exports = { apiRequest, listTables, addRecord };
    
  2. Prevent execution during import by guarding the CLI entry point:
    javascript
    if (require.main === module) {
        main();
    }
    
  3. Remove hardcoded Base, table, and record values from main(). Require explicit destination and field arguments.
  4. Keep library modules free of network and mutation side effects during initialization.
  5. Add tests verifying that require('./add_task') performs no network requests and that addRecord is exported.
  6. Update the README and SKILL.md so the documented API exactly matches the implementation.
  7. Apply the same require.main === module protection to add_task_dynamic.js.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (4)

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

This markdown file lists FEISHU_APP_ID and FEISHU_APP_SECRET as required configuration, but provides no warning that these are sensitive credentials or guidance on protecting them. For skill documentation, omitting any notice about privacy or credential handling can leave users unaware of the sensitivity of the required setup.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The documentation explicitly lists required credentials (FEISHU_APP_ID and FEISHU_APP_SECRET) but provides no warning about treating them as secrets, avoiding hardcoding, or preventing accidental exposure in source control and logs. While this does not expose a secret by itself, it normalizes unsafe handling of credentials and increases the chance that users will store or share them insecurely.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency uses a caret range (^16.3.1), which permits automatic installation of newer minor/patch releases rather than a single fixed version. This can introduce supply-chain risk if an upstream release is compromised or contains an unexpected breaking/security change, though the package itself is common and nothing else in this file suggests malicious intent.

Content

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

json
"version": "1.0.0",
  "description": "Feishu Bitable Manipulation",
  "dependencies": {
    "dotenv": "^16.3.1",
    "node-fetch": "^2.7.0"
  }
}

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency uses a caret range (^2.7.0), allowing npm to resolve to newer releases within the major version. This weakens build reproducibility and increases exposure to supply-chain compromise or unintended dependency changes, although in this context it appears more like routine package management than deliberate abuse.

Content

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

json
"description": "Feishu Bitable Manipulation",
  "dependencies": {
    "dotenv": "^16.3.1",
    "node-fetch": "^2.7.0"
  }
}