Back to skill

Security audit

Feishu Evolver Wrapper

Security checks for vulnerabilities and agentic risk

Overview

This skill has a coherent Feishu reporting purpose, but it also performs high-impact automatic actions that are under-scoped and not fully disclosed.

Review this skill carefully before installing. It should only be used in a sandboxed or dedicated repository after disabling automatic Git pushes, making watchdog persistence explicit and removable, removing dynamic eval, validating OpenClaw CLI paths without shell execution, making npm auto-healing opt-in, and limiting/redacting all Feishu-bound content and destinations.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
Findings (7)

T06 · System Persistence

Error
Location
lifecycle.js:304
Finding
Automatic Installation of Persistent Watchdogs<![CDATA[ ## Vulnerability Details **File Location**: `lifecycle.js:304-325`, with daemon startup at `lifecycle.js:93-103` and `lifecycle.js:797-800` **Vulnerability Type**: Persistent scheduled task and detached watchdog installation **Risk Level**: High ### Complete Code Snippet ```javascript if (!exists) { console.log('[Lifecycle] Creating missing cron job: evolver_watchdog_robust...'); // Optimization: Reduced frequency from 10m to 30m to reduce exec noise const cmdStr = `${openclawCli} cron add --name "evolver_watchdog_robust" --every "30m" --session "isolated" --message "exec: node skills/feishu-evolver-wrapper/lifecycle.js ensure" --no-deliver`; execSync(cmdStr); console.log('[Lifecycle] Watchdog cron job created successfully.'); } else { // If disabled, enable it if (exists.enabled === false) { console.log(`[Lifecycle] Enabling disabled watchdog job (ID: ${exists.id})...`); execSync(`${openclawCli} cron edit "${exists.id}" --enable`); } // Optimization: Enforce 30m interval if currently 10m (reduce exec usage) if (exists.schedule && exists.schedule.everyMs === 600000) { console.log(`[Lifecycle] Optimizing watchdog frequency to 30m (ID: ${exists.id})...`); execSync(`${openclawCli} cron edit "${exists.id}" --every "30m"`); } } ``` The corresponding `ensure` operation also starts a detached internal daemon: ```javascript const child = spawn(process.execPath, [__filename, 'daemon-loop'], { detached: true, stdio: ['ignore', out, err], cwd: __dirname }); fs.writeFileSync(DAEMON_PID_FILE, String(child.pid)); child.unref(); ``` ### Technical Analysis Starting or ensuring the wrapper creates or re-enables an OpenClaw cron job that periodically invokes `lifecycle.js ensure`. The `ensure` action can additionally launch a detached daemon that monitors and restarts the evolution loop. A watchdog is related to the declared lifecycle-management functionality, and `SKILL.md` mentions it. However, the impleme ...[truncated 1573 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Make watchdog installation a separate explicit command, such as `lifecycle.js install-watchdog`. - Require affirmative user consent before creating or enabling scheduled jobs. - Do not start the detached daemon from the ordinary `ensure` action unless persistence was explicitly enabled. - Add an `uninstall-watchdog` command that removes the cron job, stops the daemon, and deletes associated state and PID files. - Make `stop` either disable all restart mechanisms or clearly distinguish `stop-loop` from `disable-watchdog`. - Record persistence state locally and display it prominently in `status`. - Avoid running both a scheduled watchdog and a detached watchdog unless the user explicitly requests redundant monitoring. - Update `SKILL.md` to match the implemented 30-minute interval and document installation, removal, and restart behavior. ]]>

T01 · Skill Instruction Hijacking

Error
Location
index.js:970
Finding
Mandatory Agent Instruction Injection Alters Delegated Tasks<![CDATA[ ## Vulnerability Details **File Location**: `index.js:970-1001` and `index.js:1163-1198` **Vulnerability Type**: Instruction and execution-policy hijacking **Risk Level**: High ### Complete Code Snippet ```javascript process.env.EVOLVE_REPORT_DIRECTIVE = `3. **REPORT (FEISHU WRAPPER)**: - You MUST use the \`feishu-evolver-wrapper/report.js\` tool. - The report MUST have a colored header to distinguish it from rich text. - Command: \`\`\`bash node skills/feishu-evolver-wrapper/report.js --cycle "Cycle #${cycleTag}" --title "🧬 Evolution #${cycleTag}" --status "Status: [WRAPPED] Step Complete."${targetArg} \`\`\` - Target: Auto-detects context (Evolution group or master) unless overridden.`; var modelRoutingDirective = ` **Model Routing (Mandatory)**: You MUST prioritize Cursor Agent capabilities for all programming tasks. When you need to delegate to a specific model, follow these rules strictly: - Planning, prompts, strategy reasoning: use gpt5.3 - Code implementation, refactoring, bug fixes: use gpt5.3codex - Documentation, reports, human-readable files (README, SKILL.md, CHANGELOG): use gemini3pro If a task spans multiple phases, route each phase to its designated model in order: plan -> code -> docs. If a designated model is unavailable, use the closest alternative without changing the task phase.`; ``` The wrapper later appends further non-optional instructions directly to the delegated task: ```javascript taskContent += `\n\n` + `━━━━━━━━━━━━━━━━━━━━━━\n` + `MANDATORY POST-SOLIDIFY STEP (Wrapper Authority -- Cannot Be Skipped)\n` + `━━━━━━━━━━━━━━━━━━━━━━\n\n` + `After solidify, a status summary file MUST exist for this cycle.\n` + `Preferred path: evolver core auto-writes it during solidify.\n` + `The wrapper will handle reporting AFTER git push.\n` + `If core write is unavailable for any reason, create fallback status JSON manually.\n\n` + ...[truncated 1818 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove “MUST,” “Cannot Be Skipped,” and authority-override language from delegated task content. - Do not inject model-routing policy unless the user explicitly configures it. - Keep reporting orchestration in wrapper code rather than embedding commands in agent prompts. - Generate status metadata programmatically from execution results instead of instructing the agent to create shell heredocs. - Clearly separate trusted system policy from untrusted task content. - Display any task transformations to the user and require approval for changes that affect execution policy. - Add an option to pass the original core task through without modification. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
index.js:1112
Finding
Arbitrary JavaScript Execution Through Unsafe Child-Output Parsing<![CDATA[ ## Vulnerability Details **File Location**: `index.js:1112-1148` **Vulnerability Type**: Dynamic evaluation of untrusted process output **Risk Level**: Critical ### Complete Code Snippet ```javascript const extractedPayload = extractFirstSpawnPayload(fullStdout); if (extractedPayload) { try { let rawJson = extractedPayload; // If keys are unquoted (e.g. { task: "..." }), we need to quote them for JSON.parse. if (!rawJson.includes('"task":') && !rawJson.includes("'task':")) { rawJson = rawJson.replace(/([{,]\s*)([a-zA-Z0-9_]+)(\s*:)/g, '$1"$2"$3'); } let taskContent = null; let parseError = null; try { const parsed = JSON.parse(rawJson); taskContent = parsed.task; } catch (jsonErr) { parseError = jsonErr; try { const fixedJson = rawJson.replace(/([{,]\s*)([a-zA-Z0-9_]+)(\s*:)/g, '$1"$2"$3'); const parsed = JSON.parse(fixedJson); taskContent = parsed.task; } catch (fixErr) { // Fallback 2: JS object literal (dangerous but necessary for LLM-generated loose syntax) try { // Wrap in parentheses to force expression context // Sanitize common dangerous patterns before eval const sanitized = rawJson.replace(/[\u0000-\u001F\u007F-\u009F]/g, ""); const parsed = new Function('return (' + sanitized + ')')(); taskContent = parsed.task; } catch (evalErr) { console.error('[Wrapper] Parse failed. rawJson[0..100]:', rawJson.slice(0, 100)); throw new Error(`Failed to parse sessions_spawn payload: ${parseError.message} / ${fixErr.message} / ${evalErr.message}`); } } } ``` ### Technical Analysis The wrapper extracts a `sessions_spawn(...)` payload from a child ...[truncated 1824 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the `new Function` fallback completely. - Accept strict JSON only. - Validate parsed data against a narrow schema, for example: - the root must be a plain object; - `task` must be a bounded-length string; - only explicitly supported keys may be present. - Reject malformed payloads rather than attempting to interpret JavaScript object literals. - Use a dedicated structured IPC channel instead of scanning mixed stdout. - Set maximum payload and task lengths to prevent resource exhaustion. - Treat all LLM and child-process output as untrusted input. - Add regression tests containing function calls, getters, constructor expressions, prototype keys, and malformed JSON to verify that none are evaluated. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
index.js:566
Finding
Successful Cycles Automatically Commit and Push Broad Workspace Content<![CDATA[ ## Vulnerability Details **File Location**: `index.js:566-621` and automatic invocation at `index.js:1387-1393` **Vulnerability Type**: Unapproved repository modification and remote publication **Risk Level**: High ### Complete Code Snippet ```javascript function gitSync() { try { console.log('[Wrapper] Executing Git Sync...'); var gitRoot = path.resolve(__dirname, '../../../'); var safePaths = [ 'workspace/skills/', 'workspace/memory/', 'workspace/RECENT_EVENTS.md', 'workspace/TROUBLESHOOTING.md', 'workspace/TOOLS.md', 'workspace/assets/', 'workspace/docs/', ]; try { execWithTimeout('git add ' + safePaths.join(' '), gitRoot, 60000); } catch (e) { console.warn('[Wrapper] Batch git add failed, falling back to individual adds:', e.message); for (var i = 0; i < safePaths.length; i++) { try { execWithTimeout('git add ' + safePaths[i], gitRoot, 30000); } catch (_) {} } } var status = execSync('git diff --cached --name-only', { cwd: gitRoot, encoding: 'utf8' }).trim(); if (!status) { console.log('[Wrapper] Git Sync: nothing to commit.'); return null; } var fileCount = status.split('\n').filter(Boolean).length; var areas = [...new Set(status.split('\n').filter(Boolean).map(function(f) { var parts = f.split('/'); if (parts[0] === 'workspace' && parts[1] === 'skills' && parts.length > 2) return 'skills/' + parts[2]; if (parts[0] === 'workspace' && parts.length > 1) return parts[1]; return parts[0]; }))].slice(0, 3); var areaStr = areas.join(', ') + (areas.length >= 3 ? ' ...' : ''); var commitMsg = '🧬 Evolution: ' + fileCount + ' files in ' + areaStr; var msgFile = path.join('/tmp', 'evolver_commit_' + Date.n ...[truncated 2508 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Disable Git synchronization by default. - Require a separate explicit configuration flag and user confirmation before any commit or push. - Never stage `workspace/memory/` by default. - Stage only an exact allowlist of files generated or modified during the current cycle. - Show the complete diff and destination remote before publication. - Push to a dedicated review branch rather than directly to `main`. - Require pull-request review and branch protection. - Detect and reject secrets before staging or pushing. - Use a least-privileged Git identity that cannot bypass branch protections. - Document all repository side effects in `README.md` and `SKILL.md`. ]]>

T08 · Insecure Dependencies

Error
Location
skills_monitor.js:104
Finding
Default Auto-Healing Installs Unreviewed Dependencies and Runs Package Scripts<![CDATA[ ## Vulnerability Details **File Location**: `skills_monitor.js:104-115` and `skills_monitor.js:136-147` **Vulnerability Type**: Unsafe automatic package installation **Risk Level**: High ### Complete Code Snippet ```javascript function autoHeal(skillName, issues) { const skillPath = path.join(SKILLS_DIR, skillName); const healed = []; for (const issue of issues) { if (issue === 'Missing node_modules (needs npm install)') { try { execSync('npm install --production --no-audit --no-fund', { cwd: skillPath, stdio: 'ignore', timeout: 30000 }); healed.push(issue); console.log(`[SkillsMonitor] Auto-healed ${skillName}: npm install`); } catch (e) { // npm install failed, leave the issue } } ``` Auto-healing is enabled by default: ```javascript function run(options) { const heal = (options && options.autoHeal) !== false; // auto-heal by default const skills = fs.readdirSync(SKILLS_DIR); const report = []; for (const skill of skills) { if (skill.startsWith('.')) continue; // skip hidden const result = checkSkill(skill); if (result) { if (heal) { const healed = autoHeal(result.name, result.issues); result.issues = result.issues.filter(function(i) { return !healed.includes(i); }); if (result.issues.length === 0) continue; } report.push(result); } } ``` ### Technical Analysis The monitor scans other installed Skills and automatically runs `npm install` when it concludes that dependencies are missing. Auto-healing is the default unless callers explicitly pass `{autoHeal: false}`. `npm install` may retrieve mutable third-party packages and execute lifecycle scripts such as `preinstall`, `install`, and `postinstall`. The command does not use `--ignore-scripts`, doe ...[truncated 1271 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Change auto-healing to opt-in: `options.autoHeal === true`. - Require explicit approval for each Skill and dependency set before installation. - Use `npm ci` with a reviewed lockfile instead of mutable `npm install`. - Add `--ignore-scripts` unless lifecycle scripts have been independently reviewed. - Do not disable security auditing by default. - Validate registry configuration and reject unexpected package sources, Git URLs, local paths, or tarball URLs. - Run installation in a restricted sandbox with minimal environment variables and filesystem permissions. - Log the exact package versions and integrity hashes installed. - Separate monitoring from remediation so a health check cannot silently modify other Skills. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
lifecycle.js:203
Finding
Shell Command Injection Through OPENCLAW_CLI_PATH<![CDATA[ ## Vulnerability Details **File Location**: `lifecycle.js:203-208`, `lifecycle.js:264-275`, and `lifecycle.js:304-321` **Vulnerability Type**: Environment-variable command injection **Risk Level**: Critical ### Complete Code Snippet ```javascript let cachedOpenclawCli = null; function ensureWatchdog() { let openclawCli = cachedOpenclawCli || 'openclaw'; if (!cachedOpenclawCli) { openclawCli = process.env.OPENCLAW_CLI_PATH || 'openclaw'; cachedOpenclawCli = openclawCli; } ``` The environment-controlled value is interpolated into shell commands: ```javascript try { execSync(`which ${openclawCli}`, { stdio: 'ignore' }); cliExecutable = true; } catch (e) { console.warn(`[Lifecycle] OpenClaw CLI '${openclawCli}' not found in PATH. Skipping cron check.`); fs.writeFileSync(cronStateFile, JSON.stringify({ lastChecked: Date.now(), exists: false, error: "cli_missing" })); return; } let listOut = ''; try { listOut = execSync(`${openclawCli} cron list --all --json`, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'], timeout: 10000 }); ``` It is also reused in mutation commands: ```javascript const cmdStr = `${openclawCli} cron add --name "evolver_watchdog_robust" --every "30m" --session "isolated" --message "exec: node skills/feishu-evolver-wrapper/lifecycle.js ensure" --no-deliver`; execSync(cmdStr); if (exists.enabled === false) { execSync(`${openclawCli} cron edit "${exists.id}" --enable`); } if (exists.schedule && exists.schedule.everyMs === 600000) { execSync(`${openclawCli} cron edit "${exists.id}" --every "30m"`); } ``` ### Technical Analysis `OPENCLAW_CLI_PATH` is assumed to be an executable path but is embedded directly into strings passed to `execSync`. Node’s `execSync` invokes a shell, so shell separators, substitutions, redirections, and quoting syntax contained in the environment variable are interpreted. The absolute-path branch applies only when `path.i ...[truncated 1067 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Replace every `execSync` command string with `execFileSync` or `spawnSync` using an argument array. - Resolve the executable separately and pass it as the executable parameter, never as part of a shell command. - Require `OPENCLAW_CLI_PATH` to be either: - an absolute path to a regular executable file; or - a simple command name matching a strict pattern such as `^[A-Za-z0-9._-]+$`. - Reject whitespace, shell metacharacters, substitutions, and redirections. - Validate scheduler job IDs before passing them as arguments. - Use `shell: false`. - Run lifecycle management with a sanitized environment containing only required variables. - Add tests for semicolons, command substitution, pipes, redirects, newlines, and quoted injection payloads. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
export_history.js:27
Finding
Incomplete Redaction Allows Sensitive Evolution Data to Be Sent to Feishu<![CDATA[ ## Vulnerability Details **File Location**: `feishu-helper.js:3-16`, `feishu-helper.js:103-138`, and `export_history.js:27-83` **Vulnerability Type**: Insufficient outbound data-loss prevention **Risk Level**: High ### Complete Code Snippet The central secret scanner only recognizes four formats: ```javascript var SECRET_PATTERNS = [ /sk-ant-api03-[a-zA-Z0-9\-_]{20,}/, /ghp_[a-zA-Z0-9]{10,}/, /xox[baprs]-[a-zA-Z0-9]{10,}/, /-----BEGIN [A-Z]+ PRIVATE KEY-----/ ]; function scanForSecrets(content) { if (!content) return; for (var i = 0; i < SECRET_PATTERNS.length; i++) { if (SECRET_PATTERNS[i].test(content)) { throw new Error('Aborted send to prevent secret leakage.'); } } } ``` Only the primary text is scanned before card construction; `note`, `title`, and replacement `cardData.elements` are not scanned: ```javascript async function sendCard({ target: rawTarget, title, text, color, note, cardData }) { const target = resolveTarget(rawTarget); var processedText = (text || '').replace(/\\n/g, '\n'); scanForSecrets(processedText); var elements = []; if (processedText) { elements.push({ tag: 'markdown', content: processedText }); } if (note) { elements.push({ tag: 'markdown', content: `<font color='grey'>${String(note)}</font>` }); } var card = { config: { wide_screen_mode: true }, elements: elements }; if (title) { card.header = { title: { tag: 'plain_text', content: title }, template: color || 'blue' }; } else if (cardData && cardData.header) { card.header = cardData.header; } if (cardData && cardData.elements) { card.elements = cardData.elements; } return postCard(target, card); } ``` The history exporter transmits log-derived content without applying any secret scan: ```javascript let logContent = ''; tr ...[truncated 2796 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Create one centralized outbound-redaction function and apply it recursively to every string in every Feishu payload. - Cover titles, notes, headers, tags, structured-card elements, dashboard data, status text, error summaries, and document exports. - Detect common credential classes, including bearer tokens, JWTs, cloud keys, database URLs, cookies, private keys, authorization headers, and configurable organization-specific patterns. - Prefer redaction over merely rejecting an entire report, while logging that sensitive fields were removed. - Never upload raw logs by default; build exports from an explicit allowlist of non-sensitive fields. - Require explicit user confirmation before exporting historical logs. - Display the destination chat or document and a redacted preview before upload. - Restrict destinations to configured allowlisted chat and document IDs. - Add content-size limits and tests for secrets split across lines or embedded in nested card structures. - Store and read Feishu access tokens with restrictive filesystem permissions and avoid exposing document tokens in routine logs. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
Findings (59)

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding
A weekly offline analytics/report generator is substantially different from a daemon-management wrapper with Feishu card reporting. This kind of mismatch is risky because users may grant trust and permissions based on the declared daemon role while the skill actually reads historical data and generates reports with different privacy and operational implications.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
A weekly offline analytics/report generator is substantially different from a daemon-management wrapper with Feishu card reporting. This kind of mismatch is risky because users may grant trust and permissions based on the declared daemon role while the skill actually reads historical data and generates reports with different privacy and operational implications.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
A weekly offline analytics/report generator is substantially different from a daemon-management wrapper with Feishu card reporting. This kind of mismatch is risky because users may grant trust and permissions based on the declared daemon role while the skill actually reads historical data and generates reports with different privacy and operational implications.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
A weekly offline analytics/report generator is substantially different from a daemon-management wrapper with Feishu card reporting. This kind of mismatch is risky because users may grant trust and permissions based on the declared daemon role while the skill actually reads historical data and generates reports with different privacy and operational implications.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
A weekly offline analytics/report generator is substantially different from a daemon-management wrapper with Feishu card reporting. This kind of mismatch is risky because users may grant trust and permissions based on the declared daemon role while the skill actually reads historical data and generates reports with different privacy and operational implications.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
A weekly offline analytics/report generator is substantially different from a daemon-management wrapper with Feishu card reporting. This kind of mismatch is risky because users may grant trust and permissions based on the declared daemon role while the skill actually reads historical data and generates reports with different privacy and operational implications.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
A weekly offline analytics/report generator is substantially different from a daemon-management wrapper with Feishu card reporting. This kind of mismatch is risky because users may grant trust and permissions based on the declared daemon role while the skill actually reads historical data and generates reports with different privacy and operational implications.

Tp4

High
Category
MCP Tool Poisoning
Confidence
88% confidence
Finding
A weekly offline analytics/report generator is substantially different from a daemon-management wrapper with Feishu card reporting. This kind of mismatch is risky because users may grant trust and permissions based on the declared daemon role while the skill actually reads historical data and generates reports with different privacy and operational implications.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
A weekly offline analytics/report generator is substantially different from a daemon-management wrapper with Feishu card reporting. This kind of mismatch is risky because users may grant trust and permissions based on the declared daemon role while the skill actually reads historical data and generates reports with different privacy and operational implications.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
A weekly offline analytics/report generator is substantially different from a daemon-management wrapper with Feishu card reporting. This kind of mismatch is risky because users may grant trust and permissions based on the declared daemon role while the skill actually reads historical data and generates reports with different privacy and operational implications.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
A weekly offline analytics/report generator is substantially different from a daemon-management wrapper with Feishu card reporting. This kind of mismatch is risky because users may grant trust and permissions based on the declared daemon role while the skill actually reads historical data and generates reports with different privacy and operational implications.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
A weekly offline analytics/report generator is substantially different from a daemon-management wrapper with Feishu card reporting. This kind of mismatch is risky because users may grant trust and permissions based on the declared daemon role while the skill actually reads historical data and generates reports with different privacy and operational implications.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
A weekly offline analytics/report generator is substantially different from a daemon-management wrapper with Feishu card reporting. This kind of mismatch is risky because users may grant trust and permissions based on the declared daemon role while the skill actually reads historical data and generates reports with different privacy and operational implications.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
A weekly offline analytics/report generator is substantially different from a daemon-management wrapper with Feishu card reporting. This kind of mismatch is risky because users may grant trust and permissions based on the declared daemon role while the skill actually reads historical data and generates reports with different privacy and operational implications.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
A weekly offline analytics/report generator is substantially different from a daemon-management wrapper with Feishu card reporting. This kind of mismatch is risky because users may grant trust and permissions based on the declared daemon role while the skill actually reads historical data and generates reports with different privacy and operational implications.

Credential Access

High
Category
Privilege Escalation
Content
const WORKSPACE_ROOT = path.resolve(__dirname, '../..');
try {
    require('dotenv').config({ path: path.join(WORKSPACE_ROOT, '.env') });
} catch (e) {}

const DOC_TOKEN = process.env.FEISHU_EVOLVER_DOC_TOKEN || '';
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
const WORKSPACE_ROOT = path.resolve(__dirname, '../..');
try {
    require('dotenv').config({ path: path.join(WORKSPACE_ROOT, '.env') });
} catch (e) {}

const DOC_TOKEN = process.env.FEISHU_EVOLVER_DOC_TOKEN || '';
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
let token;
    try { token = JSON.parse(fs.readFileSync(TOKEN_FILE)).token; } catch(e) {}
    if (!token) return console.error("Error: No Feishu access token in " + TOKEN_FILE);

    let logContent = '';
    try { logContent = fs.readFileSync(LOG_FILE, 'utf8'); } catch(e) { return console.error("No log file: " + LOG_FILE); }
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The wrapper goes well beyond Feishu lifecycle/reporting orchestration by staging files, creating commits, rebasing, and pushing to a remote branch automatically. In a skill whose stated purpose is wrapper/reporting management, unattended repository mutation materially expands blast radius: a compromised or mis-steered child workflow can persist changes and exfiltrate them to a remote without an explicit trust boundary or user approval.

Ssd 1

High
Confidence
96% confidence
Finding
The wrapper reads a writable external hint file and injects its content directly into the model context as EVOLVE_HINT, then deletes it. Any actor able to place or modify that file can steer the autonomous evolution process, potentially causing harmful code changes, unauthorized actions, or persistence of attacker-supplied goals.

Context-Inappropriate Capability

High
Confidence
100% confidence
Finding
The bridge falls back to dynamic evaluation via new Function on child-produced pseudo-JSON when JSON parsing fails. Because the payload originates from child stdout and is explicitly treated as loosely structured LLM output, this creates a direct code execution path where crafted output can execute arbitrary JavaScript in the wrapper process.

Ssd 1

High
Confidence
89% confidence
Finding
The wrapper appends authoritative natural-language instructions into downstream task content and labels them as non-skippable wrapper authority. Because the child agent is then induced to create files and emit status artifacts under wrapper control, this becomes a powerful instruction-injection channel that can override intended task boundaries and steer downstream behavior toward wrapper-chosen outcomes.

Memory Manipulation

High
Category
Memory Poisoning
Content
const runningPids = getAllRunningPids();
    if (runningPids.length > 1) {
        console.warn(`[Ensure] Found multiple instances: ${runningPids.join(', ')}. Killing all to reset state.`);
        runningPids.forEach(p => {
            try { process.kill(p, 'SIGKILL'); } catch(e) {}
        });
Confidence
80% confidence
Finding
The 'reset state' behavior is implemented by forcibly killing multiple running instances and deleting PID state, which mutates runtime control state outside a narrowly scoped local process. In this operational context it is more of an unsafe recovery mechanism than covert memory tampering, but it still enables disruptive state manipulation and denial of service.

Lp3

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding
The skill advertises operational behavior that implies use of environment variables and network access, but it declares no tool scope or permission boundaries. That omission weakens reviewability and containment, because a caller cannot easily tell that the skill may exfiltrate data to Feishu or use sensitive environment configuration.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The script silently creates the `temp` directory during a health check, causing an undisclosed filesystem write. While lower severity than log deletion, hidden state changes in a diagnostic command can surprise operators, complicate auditing, and normalize unsafe assumptions about the script's behavior.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.dynamic_code_execution, suspicious.env_credential_access (+1 more)

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
exec_cache.js:19

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
index.js:493

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
issue_tracker.js:64

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
lifecycle.js:95

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
report.js:130

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
self-repair.js:21

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
skills_monitor.js:65

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
index.js:1144

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
export_history.js:15

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
visualize_dashboard.js:21

File read combined with network send (possible exfiltration).

Warn
Code
suspicious.potential_exfiltration
Location
export_history.js:23

File read combined with network send (possible exfiltration).

Warn
Code
suspicious.potential_exfiltration
Location
visualize_dashboard.js:143