Back to skill

Security audit

AI搭子匹配平台

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly coherent and local-only, but it collects AI usage metadata and has a path-validation bug that can write JSON files outside its intended data folder.

Review this skill before installing. It does not show network exfiltration, hidden install hooks, external dependencies, or raw session-log reading, but it profiles and stores AI usage metadata locally. Install only if you are comfortable with that profiling, and avoid running its save command on untrusted JSON until the date field is strictly validated and trigger wording is narrowed or confirmation is added.

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 (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/token-collector.js:27
Finding

Path Traversal Allows Overwriting Arbitrary JSON Files

Content
View full analysis

Vulnerability Details

File Location: scripts/token-collector.js, lines 27-31; attacker-controlled input enters the sink at lines 64-72
Vulnerability Type: Path traversal and arbitrary file overwrite
Risk Level: High

Vulnerable Code

javascript
function saveDailyData(date, data) {
  ensureDataDirs();
  data.collectedAt = new Date().toISOString();
  const filePath = path.join(DAILY_DIR, `${date}.json`);
  fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');
  return filePath;
}

The date value is taken directly from externally supplied JSON without format or path validation:

javascript
function save(jsonStr) {
  ensureDataDirs();
  let data;
  try {
    data = JSON.parse(jsonStr);
  } catch (e) {
    console.error('❌ 无效的 JSON 输入');
    process.exit(1);
  }

  if (!data.date) {
    console.error('❌ 数据缺少 date 字段');
    process.exit(1);
  }

  const filePath = saveDailyData(data.date, data);

Technical Analysis

The save command accepts JSON through a command-line argument. Its date property is interpolated directly into a file path:

javascript
path.join(DAILY_DIR, `${date}.json`)

Checking only that data.date is truthy does not prevent path separators or traversal sequences such as ../. Node.js normalizes these sequences when constructing the path, allowing the resulting destination to escape the intended data/daily/ directory.

The appended .json extension limits the primitive to files ending in .json, but this still includes security-relevant project files such as package.json and config.json, as well as JSON files elsewhere that are writable by the Node.js process.

This behavior exceeds the minimum filesystem privileges required by the declared functionality. Saving daily statistics requires access only to a filename derived from a strict calendar date inside data/daily/, not arbitrary writable JSON pat ...[truncated 1811 chars]

Remediation
View remediation

Remediation Suggestions

  1. Validate date against an exact date format before using it in a path:

    javascript
    function validateDate(date) {
      if (typeof date !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(date)) {
        throw new Error('Date must use YYYY-MM-DD format');
      }
    
      const parsed = new Date(`${date}T00:00:00Z`);
      if (
        Number.isNaN(parsed.getTime()) ||
        parsed.toISOString().slice(0, 10) !== date
      ) {
        throw new Error('Date is not a valid calendar date');
      }
    }
    
  2. Resolve the destination and enforce directory containment:

    javascript
    function saveDailyData(date, data) {
      ensureDataDirs();
      validateDate(date);
    
      const baseDir = path.resolve(DAILY_DIR);
      const filePath = path.resolve(baseDir, `${date}.json`);
    
      if (path.dirname(filePath) !== baseDir) {
        throw new Error('Invalid destination path');
      }
    
      const output = {
        ...data,
        date,
        collectedAt: new Date().toISOString()
      };
    
      fs.writeFileSync(filePath, JSON.stringify(output, null, 2), {
        encoding: 'utf-8',
        flag: 'w',
        mode: 0o600
      });
    
      return filePath;
    }
    
  3. Apply the same strict date validation to loadDailyData(date), because that exported function constructs a path from its argument using the same pattern.

  4. Validate the complete input structure, including numeric ranges, object types, array sizes, and permitted property names.

  5. Run the Skill with a restricted account that cannot modify application code, package metadata, or unrelated users' files.

  6. Add regression tests covering values such as ../config, ../../package, absolute paths, encoded separators, malformed dates, and invalid calendar dates.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (8)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
3. 执行保存:`node scripts/token-collector.js save '<json>'`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
4. 执行画像生成:`node scripts/profile-generator.js generate`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
4. 执行画像生成:`node scripts/profile-generator.js generate`

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger phrases are broad, generic, and tied to common conversational terms such as '匹配', '用户画像', and '使用报告', which can cause the skill to activate in contexts the user did not intend. Because this skill instructs the agent to collect session-level usage data via session_status and persist it locally, accidental invocation increases the chance of unnecessary profiling or data handling beyond the user's clear informed intent.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This markdown file presents all headings, field descriptions, and explanatory text in Chinese, which effectively forces a specific language for users reading the skill documentation. The policy allows locale constraints only when the skill offers user choice or clearly documents a justified regional limitation, neither of which appears here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The user-facing instruction says 请对 AI 说"生成我的AI画像"来触发数据采集。, which requires a specific Chinese phrase to activate the workflow. Similar hard-coded Chinese prompts also appear elsewhere in the file, and there is no indication that users may use another language or locale.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

This manifest describes the skill only as an 'AI matching platform' with intelligent profiling and matching, but does not specify concrete trigger phrases, scope boundaries, or exclusion conditions. In a manifest file, such broad wording can contribute to unintended activation because many user requests about profiles, matching, or AI assistance could appear to fit.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

The header explicitly states '不访问 session 日志' while the implementation consumes daily records containing sessionCount, messageCount, activeHours, provider/model/tool frequencies, and installed skills via loadAllDailyData(). Even if these are aggregated rather than raw logs, the documentation asserts a stricter limitation than the code's actual data usage, creating an intent/documentation mismatch.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.