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
- Audit the SKILL.md frontmatter `name` field for traversal characters or absolute paths and correct it.
- Only install skills from trusted sources; treat a traversal name as a red flag.
- 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
- Constrain skill names to a slug pattern (^[a-z0-9][a-z0-9-]*$) at authoring time.
- Audit third-party SKILL.md frontmatter before installing.
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
- Invalid path: Directory traversal not allowed.
- No valid skills found in ${source}${subpath ? ` at path "${s
- Invalid taskId: ${taskId}
- Security violation: Null byte detected in path.
- Security violation: The path "${trimmedPath}" is outside the
AI-assisted analysis of google-gemini/gemini-cli@5024443c72 (2026-08-12).
Data as JSON: /api/errors/752da7fb4a0b8650.
Report an issue: GitHub.