Back to skill

Security audit

Feishu Calendar

Security checks for vulnerabilities and agentic risk

Overview

This Feishu calendar skill performs real calendar reads, writes, deletions, and persistent local state updates, but several high-impact actions are under-scoped and can affect unintended calendars or agent state.

Review this skill carefully before installing. Use only low-privilege Feishu test credentials, verify the target calendar explicitly, avoid running cleanup/setup routines on production calendars, and do not let synced calendar text become trusted agent instructions without sanitization.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • 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
  • 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 (3)

T02 · Agent Memory Poisoning

Error
Location
sync.js:35
Finding

Untrusted Calendar Content Is Persisted into Agent State and HEARTBEAT.md

Content
View full analysis
{ const t = parseInt(e.start_time.timestamp); return t < (Date.now()/1000 + 86400); }); if (next24h.length === 0) { calendarSection = "## 📅 Calendar (Next 24h)\n\n- No upcoming events in the next 24 hours.\n"; } else { next24h.forEach(e => { const start = getTimestampCST(parseInt(e.start_time.timestamp) * 1000).split(' ')[1]; calendarSection += `- [ ] ${start} - ${e.summary}\n`; }); } const calendarRegex = /## (?:📅 )?Calendar.*?(?=\n## |$)/s; if (calendarRegex.test(heartbeatContent)) { heartbeatContent = heartbeatContent.replace(calendarRegex, calendarSection.trim()); } else { const insertPos = heartbeatContent.indexOf('## Morning'); if (insertPos !== -1) { heartbeatContent = heartbeatContent.slice(0, insertPos) + calendarSection + "\n" + heartbeatContent.slice(insertPos); } else { heartbeatContent += "\n" + calendarSection; } } fs.writeFileSync(heartbeatPath, heartbeatContent, 'utf8'); } ``` ### Technical Analysis Calendar events are obtained from the external Feishu service and written into two persistent project-level files. In particular, `e.summary` is interpolate ...[truncated 2201 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
lib/CalendarManager.js:14
Finding

Silent Calendar Fallback Can Read or Modify an Unintended Primary Calendar

Content
View full analysis
c.summary.includes(searchKeyword) || c.summary.includes("OpenClaw")); if (!target && calendars.length > 0) target = calendars[0]; // Fallback return target; } catch (e) { console.error(`[CalendarManager] Error getting calendar: ${e.message}`); return null; } } async listEvents(calendarId, startTime = Date.now(), endTime = Date.now() + 86400 * 3000, pageSize = 50) { try { const params = { start_time: String(Math.floor(startTime / 1000)), end_time: String(Math.floor(endTime / 1000)), page_size: pageSize }; let res = await this.client.calendar.calendarEvent.list({ path: { calendar_id: calendarId }, params: params }); if (res.code !== 0) { if (calendarId !== 'primary') { console.log(`[CalendarManager] Access failed for ID ${calendarId}, falling back to 'primary'...`); res = await this.client.calendar.calendarEvent.list({ path: { calendar_id: 'primary' }, params: params }); } } if (res.code !== 0) throw new Error(`Fetch events failed: ${res.msg}`); return res.data.items || []; } catch (e) { console.error(`[ ...[truncated 4953 chars]
Remediation
View remediation

other

Note
Location
search_cal.js:4
Finding

Calendar Search Utility Hard-Codes a Personal Identity and Logs Matching Calendar Identifiers

Content
View full analysis
{ // Attempt 2: Search for calendar console.log("Searching for Master's calendar..."); try { const res = await client.calendar.calendar.search({ data: { query: "张昊阳" // Search by name? } }); if (res.code === 0 && res.data.items) { console.log("Found Calendars:", res.data.items.map(c => `${c.summary} (${c.calendar_id})`)); } else { console.log("Search failed or empty:", res); } } catch(e) { console.error("Search Error:", e.message); } })(); ``` ### Technical Analysis The script reads `OPENCLAW_MASTER_ID` but never uses it. Instead, each execution searches for a hard-coded individual. This conflicts with the generic documented behavior of finding a calendar by name or summary because the user cannot provide the search term. The script then logs every returned calendar summary and calendar ID. Calendar IDs can be operationally sensitive identifiers, and logs may be retained or exposed to users who do not otherwise need them. This is not credential theft or privilege escalation: the search remains limited to results available to the configured Feishu application. It is nevertheless an undeclared, identity-specific privacy concern and can result in unnecessary metadata disclosure. ### Attack Path 1. A user runs the documented `search_cal.js` utility expecting a generic calendar search. 2. The script ignores user intent and the loaded `OPENCLAW_MASTER_ID`. 3. It always submits the embedded personal name to the Feishu calendar ...[truncated 690 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
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (39)

Known Vulnerable Dependency: protobufjs==7.5.4 — 12 advisory(ies): CVE-2026-44294 (protobuf.js: Denial of service from crafted field names in generated code); CVE-2026-44293 (protobuf.js: Code injection through bytes field defaults in generated toObject c); CVE-2026-44289 (protobuf.js: Denial of service through unbounded protobuf recursion) +9 more

Critical
Category
Supply Chain
Confidence
90% confidence
Finding

protobufjs is present with hasInstallScript enabled and multiple critical advisories related to parsing, recursion, and generated code behavior. In a skill using the Lark/Feishu SDK, protobuf handling may be part of message processing or API transport, and if untrusted protobuf content or schema-driven generation is involved, this can result in denial of service or unsafe code-generation paths.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 38)May include surrounding context.

md
2. **Execute**: Run `create.js` with `--attendees` set to the requester's ID.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script performs irreversible deletion of calendar events without user confirmation, dry-run support, or any secondary validation beyond an empty-title check. In an automation or agent context, this increases the risk of accidental destructive actions against the wrong calendar or legitimate events with malformed metadata.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The module can create remote calendar events using arbitrary caller-supplied eventData, and if creation fails on the requested calendar it silently retries against the 'primary' calendar. In a skill with no declared purpose or guardrails, this enables unintended modification of a user's primary calendar and increases the blast radius of misuse or prompt-injection-driven actions.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: axios==1.13.4 — 16 advisory(ies): CVE-2026-44494 (axios Vulnerable to Full Man-in-the-Middle via Prototype Pollution Gadget in `co); CVE-2026-44495 (axios Vulnerable to Credential Theft and Response Hijacking via Prototype Pollut); CVE-2025-62718 (Axios has a NO_PROXY Hostname Normalization Bypass that Leads to SSRF) +13 more

High
Category
Supply Chain
Confidence
88% confidence
Finding

axios is a network-facing HTTP client and the listed advisories include SSRF/proxy bypass and prototype-pollution-related request manipulation issues. In a calendar integration skill that likely makes outbound API requests, vulnerable HTTP client behavior can be reachable and may allow request redirection, credential leakage, or abuse of trusted network paths if attacker-controlled URLs, headers, or proxy settings are involved.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: form-data==4.0.5 — 1 advisory(ies): CVE-2026-12143 (form-data: CRLF injection in form-data via unescaped multipart field names and f)

High
Category
Supply Chain
Confidence
80% confidence
Finding

form-data is commonly used to construct multipart requests, and CRLF injection in field names/filenames can lead to malformed requests, header injection, or request smuggling-like behavior when attacker-controlled multipart metadata is included. While exploitability depends on whether the skill ever builds multipart bodies from untrusted input, the dependency issue itself is real.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: ws==8.19.0 — 2 advisory(ies): CVE-2026-45736 (ws: Uninitialized memory disclosure); CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
81% confidence
Finding

ws is a WebSocket implementation with advisories for memory disclosure and memory-exhaustion denial of service. If the Feishu/Lark SDK uses WebSockets for event streams or bot connectivity, a remote party may be able to trigger resource exhaustion or potentially expose process memory through malformed frames, making this relevant for long-lived agent processes.

Content

No source excerpt is available for this finding.

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 · check.js (reported line 3)May include surrounding context.

js
const Lark = require('@larksuiteoapi/node-sdk');
require('dotenv').config({ path: require('path').resolve(__dirname, '../../.env') });

const APP_ID = process.env.FEISHU_APP_ID;
const APP_SECRET = process.env.FEISHU_APP_SECRET;

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 · check.js (reported line 9)May include surrounding context.

js
const Lark = require('@larksuiteoapi/node-sdk');
require('dotenv').config({ path: require('path').resolve(__dirname, '../../.env') });

const APP_ID = process.env.FEISHU_APP_ID;
const APP_SECRET = process.env.FEISHU_APP_SECRET;

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 · cleanup.js (reported line 2)May include surrounding context.

js
const Lark = require('@larksuiteoapi/node-sdk');
require('dotenv').config({ path: require('path').resolve(__dirname, '../../.env') });

const APP_ID = process.env.FEISHU_APP_ID;
const APP_SECRET = process.env.FEISHU_APP_SECRET;

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 · create.js (reported line 3)May include surrounding context.

js
const Lark = require('@larksuiteoapi/node-sdk');
require('dotenv').config({ path: require('path').resolve(__dirname, '../../.env') });

const APP_ID = process.env.FEISHU_APP_ID;
const APP_SECRET = process.env.FEISHU_APP_SECRET;

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/CalendarManager.js (reported line 2)May include surrounding context.

js
const Lark = require('@larksuiteoapi/node-sdk');
require('dotenv').config({ path: require('path').resolve(__dirname, '../../.env') });

const APP_ID = process.env.FEISHU_APP_ID;
const APP_SECRET = process.env.FEISHU_APP_SECRET;

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 · list_test.js (reported line 2)May include surrounding context.

js
const Lark = require('@larksuiteoapi/node-sdk');
require('dotenv').config({ path: require('path').resolve(__dirname, '../../.env') });

const APP_ID = process.env.FEISHU_APP_ID;
const APP_SECRET = process.env.FEISHU_APP_SECRET;

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 · search_cal.js (reported line 2)May include surrounding context.

js
const Lark = require('@larksuiteoapi/node-sdk');
require('dotenv').config({ path: require('path').resolve(__dirname, '../../.env') });

const APP_ID = process.env.FEISHU_APP_ID;
const APP_SECRET = process.env.FEISHU_APP_SECRET;

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 · setup_shared.js (reported line 3)May include surrounding context.

js
const Lark = require('@larksuiteoapi/node-sdk');
require('dotenv').config({ path: require('path').resolve(__dirname, '../../.env') });

const APP_ID = process.env.FEISHU_APP_ID;
const APP_SECRET = process.env.FEISHU_APP_SECRET;

Credential Access

High
Category
Privilege Escalation
Confidence
96% confidence
Finding

This code accesses application credentials by loading ../../.env, then uses FEISHU_APP_ID and FEISHU_APP_SECRET to authenticate to an external API and perform destructive and persistent actions such as deleting events and creating recurring calendar entries. In a skill context, this is dangerous because the skill gains broad credential-backed capabilities beyond simple local processing, and the shared .env path suggests possible cross-component secret access.

Content

Scanner excerpt · setup_routine.js (reported line 3)May include surrounding context.

js
const { program } = require('commander');
const Lark = require('@larksuiteoapi/node-sdk');
require('dotenv').config({ path: require('path').resolve(__dirname, '../../.env') });

const APP_ID = process.env.FEISHU_APP_ID;
const APP_SECRET = process.env.FEISHU_APP_SECRET;

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill describes setup and sync operations without warning that they use Feishu credentials to read calendars and potentially modify shared calendar state, which can mislead users and agents about the sensitivity and side effects of these commands. In this context, missing disclosure is dangerous because sync and setup routines operate on external systems and shared resources, increasing the chance of unintended data access, event propagation, or permission changes.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The documented trigger phrases are broad natural-language commands that can easily occur in ordinary conversation, causing the skill to initiate calendar event creation when the user may not have intended a state-changing action. In this skill context, the risk is heightened because the protocol directly maps the trigger to executing create.js with attendee data, which can create or modify calendar records using live Feishu credentials.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script loads Feishu app credentials from a local .env file and uses them to authenticate to a remote API, but there is no manifest, access justification, or user-consent flow explaining why this skill needs secrets. In an agent-skill context, undeclared secret handling expands the trust boundary and can enable unauthorized use of a user's tenant-integrated application credentials.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code enumerates calendars and selects a calendar to inspect without any declared purpose or guardrails limiting access to only the minimally necessary resource. In a skill ecosystem, silent remote discovery of user calendar resources is a privacy-sensitive capability and can facilitate collection of workspace metadata and event access beyond user expectations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script reads FEISHU_APP_ID and FEISHU_APP_SECRET from the environment and immediately uses them to authenticate API requests, but there is no user-facing warning, docstring, or explanatory comment describing this sensitive credential usage. For a standalone cleanup script, this omission reduces transparency about access to privileged calendar data.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The inline comments at L63-L64 express uncertainty about whether the script should delete everything except a specific event or only delete undefined ones. The implemented logic at L65 proceeds to delete all events with missing, blank, or literal 'undefined' summaries, which is a concrete behavior not aligned with the preceding stated intent options.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

With no manifest or declared purpose available, the skill's code introduces a capability to load and use sensitive credentials from disk/environment. Accessing FEISHU_APP_ID and FEISHU_APP_SECRET is a privileged behavior that is not justified by any stated skill intent in the provided context.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The code initializes a Feishu API client and later lists calendars and creates events over the network. Because no manifest or purpose is available, this external-service access is an unjustified capability relative to the declared context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The event creation request forces the timezone to 'Asia/Shanghai' for all events. This is a natural-language policy concern because it imposes a locale-specific setting on users without offering a choice or documenting that the skill is region-specific.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.