Back to skill

Security audit

Auto Optimizer

Security checks for vulnerabilities and agentic risk

Overview

The skill’s optimization purpose is understandable, but it can persistently change other skill code and metric files with weak scoping and no clear approval gate.

Review this skill carefully before installing. Its intended job involves changing other skills' code, so use it only in a version-controlled workspace, prefer preview or dry-run behavior where available, and avoid passing untrusted skill names or paths until path validation and explicit confirmation are 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
src/monitor.js:31
Finding

Path Traversal Through Unvalidated Skill Names

Content
View full analysis

Vulnerability Details

File Location: src/monitor.js:31-34, src/monitor.js:42-48, and src/monitor.js:96-111
Vulnerability Type: Path traversal leading to unauthorized local file access and modification
Risk Level: High

Vulnerable Code

javascript
record(skillName, metric) {
  const timestamp = new Date().toISOString();
  const entry = {
    skill: skillName,
    timestamp,
    ...metric,
  };

  const filePath = path.join(this.metricsPath, `${skillName}.jsonl`);
  fs.appendFileSync(filePath, JSON.stringify(entry) + '\n');

  return entry;
}
javascript
getMetrics(skillName, days = 7) {
  const filePath = path.join(this.metricsPath, `${skillName}.jsonl`);
  if (!fs.existsSync(filePath)) return [];

  const since = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();

  return fs.readFileSync(filePath, 'utf-8')
    .split('\n')
    .filter(line => line.trim())
    .map(line => JSON.parse(line))
    .filter(m => m.timestamp >= since);
}
javascript
cleanOldMetrics() {
  const cutoff = new Date(Date.now() - this.retentionDays * 24 * 60 * 60 * 1000);

  this.getMonitoredSkills().forEach(skill => {
    const filePath = path.join(this.metricsPath, `${skill}.jsonl`);
    const lines = fs.readFileSync(filePath, 'utf-8')
      .split('\n')
      .filter(line => {
        if (!line.trim()) return false;
        try {
          const metric = JSON.parse(line);
          return new Date(metric.timestamp) > cutoff;
        } catch {
          return false;
        }
      });

    fs.writeFileSync(filePath, lines.join('\n'));
  });
}

Technical Analysis

The skillName parameter is incorporated directly into a filesystem path without validation or canonical path confinement. Node.js path.join() normalizes traversal components but does not ensure that the resulting path remains beneath this.metricsPath.

A value containing parent-directory components, such as ../../target, can therefore resolve outside the i ...[truncated 2269 chars]

Remediation
View remediation

Remediation Suggestions

  1. Restrict skill identifiers to a safe allowlist

    Accept only identifiers that cannot contain path syntax:

    javascript
    function validateSkillName(skillName) {
      if (
        typeof skillName !== 'string' ||
        !/^[A-Za-z0-9_-]+$/.test(skillName)
      ) {
        throw new TypeError('Invalid skill name');
      }
    }
    
  2. Resolve and confine every generated path

    Verify that the canonical candidate remains beneath the configured metrics directory:

    javascript
    function getMetricPath(metricsPath, skillName) {
      validateSkillName(skillName);
    
      const base = path.resolve(metricsPath);
      const candidate = path.resolve(base, `${skillName}.jsonl`);
    
      if (!candidate.startsWith(base + path.sep)) {
        throw new Error('Metric path escapes the configured directory');
      }
    
      return candidate;
    }
    

    Use this helper consistently in record(), getMetrics(), and cleanOldMetrics().

  3. Reject symlinks and non-regular files

    Before reading, appending, or rewriting an existing metric file, inspect it with fs.lstatSync() and reject symbolic links and non-regular files. Where stronger guarantees are required, use file-opening flags supported by the platform to prevent symlink following and reduce time-of-check/time-of-use races.

  4. Harden metric parsing and resource limits

    Parse each line inside a controlled try/catch, enforce a maximum file size and line count, and validate record schemas before returning them. This prevents malformed or oversized files from causing avoidable denial of service.

  5. Add security regression tests

    Test and reject values including ../target, ..\\target, absolute paths, path separators, empty strings, NUL bytes, Unicode separator variants, and symlink-based escapes.

Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • 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
Findings (13)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The documentation advertises 'automatic application' of optimizations to code without any visible warning, approval gate, backup guidance, or discussion of behavioral risk. In a skill that can modify source files, this can lead users to run code-changing actions they do not fully understand, potentially introducing bugs, unsafe edits, or unintended changes across a project.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The example directly shows optimizeSkill('my-skill', { skillPath: './skills/my-skill' }), which normalizes automatic code modification as a routine action without a safety warning. Because this is executable guidance targeting a filesystem path, users may apply transformations to real codebases without review, increasing the chance of corruption, logic changes, or unsafe automated edits.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code automatically creates backups and then modifies a target skill when recommendation.autoApplicable is set, without any explicit user confirmation or warning. In a code-modifying agent context, silent filesystem changes increase the risk of unauthorized or surprising modifications, especially if recommendations can be influenced by untrusted input or upstream components.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The createBackup comment says it creates a backup, and the code constructs a .zip path at L063, implying an archive backup. However, the actual implementation at L065-L067 performs a recursive directory copy to a plain directory and returns the unused .zip path, which contradicts the apparent documented intent of the function.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The function writes directly to src/index.js, altering executable code in place without prompting the user or validating whether the target path is expected and authorized. In an agent skill that edits code automatically, this can lead to integrity issues, unintended code changes, or abuse if an attacker can influence skillPath or the recommendation flow.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The code applies an optimization plan directly via applyPlan(plan, context) with no visible confirmation, approval gate, dry-run step, or policy check in this entrypoint. Because optimization plans may alter runtime behavior or system configuration through the applier, automatic execution increases the risk of unintended or unsafe changes, especially if the plan or context is influenced by untrusted data.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The primary descriptive text is presented in Chinese, which can impose a language constraint on users. The file does not indicate that language selection is optional or that the skill is intentionally limited to a Chinese-speaking or region-specific audience.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The package description is written entirely in Chinese, which indicates a language-specific presentation without any visible opt-in, alternative locale, or justification for restricting the skill to Chinese-speaking users. Under the natural-language policy rules, locale or language constraints should be optional or clearly documented as region-specific.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The code accesses sensitive environment-derived user directory information to choose a backup path, but there is no user-facing notice that backups will be written under the user's home profile. For this rule, environment or profile access should be disclosed when it affects user data location or privacy expectations.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
73% confidence
Finding

The file contains user-facing and developer-facing natural-language text primarily in Chinese comments and identifiers' descriptions, while some returned messages are in English. This imposes inconsistent language assumptions without any opt-in or documented locale constraint, which can violate language/locale policy expectations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The code persistently appends metric entries to per-skill JSONL files under a user home directory path. Although the file header says this is a performance monitor, there is no confirmation prompt, user-facing log/print, or inline warning at the write site disclosing that user/system-derived metrics will be stored on disk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The cleanup routine removes older metric entries by rewriting each metrics file with filtered contents, which is a destructive operation. While retention behavior is implied by the class name and comments, there is no visible warning, log, or prompt at the time of deletion-like modification to inform users that historical data will be purged.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

This JavaScript test file includes user-facing natural-language text and comments in Chinese, such as the title on L002 and comment on L011, without offering a language choice or documenting a region-specific need. Per the policy, forcing a specific language without user opt-in is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.