google-gemini/gemini-cli · error

Invalid skill name: Path traversal detected.

Error message

Invalid skill name: Path traversal detected.

What it means

Security guard thrown during skill installation when a skill's name resolves to a destination path outside the target skills directory (path traversal via the skill name). isInvalidSubpath returns true if the relative path is empty, equals '..', starts with '../', or is absolute — blocking names like '../esc', '/abs', or names that resolve to the target dir itself.

Source

Thrown at packages/cli/src/utils/skillUtils.ts:187

        : Storage.getUserSkillsDir();

    if (!(await requestConsent(skills, targetDir))) {
      throw new Error('Skill installation cancelled by user.');
    }

    const resolvedTarget = path.resolve(targetDir);
    await fs.mkdir(resolvedTarget, { recursive: true });

    const installedSkills: Array<{ name: string; location: string }> = [];

    for (const skill of skills) {
      const skillName = skill.name;
      const skillDir = path.dirname(skill.location);
      const destPath = path.resolve(resolvedTarget, skillName);

      const relative = path.relative(resolvedTarget, destPath);
      if (isInvalidSubpath(relative)) {
        throw new Error('Invalid skill name: Path traversal detected.');
      }

      const exists = await fs.lstat(destPath).catch(() => null);
      if (exists) {
        onLog(`Skill "${skillName}" already exists. Overwriting...`);
        await fs.rm(destPath, { recursive: true, force: true });
      }

      await fs.cp(skillDir, destPath, { recursive: true });
      installedSkills.push({ name: skillName, location: destPath });
    }

    return installedSkills;
  } finally {
    if (tempDirToClean) {
      await fs.rm(tempDirToClean, { recursive: true, force: true });
    }
  }

View on GitHub (pinned to 5024443c72)

Solutions

  1. Audit the SKILL.md frontmatter `name` field for traversal characters or absolute paths and correct it.
  2. Only install skills from trusted sources; treat a traversal name as a red flag.
  3. Sanitize/normalize skill names before publishing so they are simple slugs.

Example fix

// before: SKILL.md frontmatter
// ---
// name: ../escape
// ---

// after
// ---
// name: my-skill
// ---
Defensive patterns

Strategy: validation

Validate before calling

const path = require('path');
function assertValidSkillName(name, targetDir) {
  const rel = path.relative(path.resolve(targetDir), path.resolve(targetDir, name));
  if (rel === '' || rel === '..' || rel.startsWith('..' + path.sep) || path.isAbsolute(rel)) {
    throw new Error(`Skill name '${name}' is invalid (traversal or empty)`);
  }
}

Type guard

const isSafeSkillName = (name, targetDir) => {
  const rel = path.relative(path.resolve(targetDir), path.resolve(targetDir, name));
  return rel !== '' && rel !== '..' && !rel.startsWith('..' + path.sep) && !path.isAbsolute(rel);
};

Prevention

When it happens

Trigger: skill.name contains traversal characters (e.g. '../foo') or is absolute, so path.relative(resolvedTarget, destPath) is flagged by isInvalidSubpath before the copy. Also triggers if skill.name resolves exactly to resolvedTarget (relative === '').

Common situations: A malicious SKILL.md declares a name with '../' to write outside the skills dir. A skill name that is an absolute path. A skill whose name, after sanitization, collapses to the target directory. Third-party skill source with crafted frontmatter.

Related errors


AI-assisted analysis of google-gemini/gemini-cli@5024443c72 (2026-08-12). Data as JSON: /api/errors/752da7fb4a0b8650. Report an issue: GitHub.