mastra-ai/mastra · error
Path traversal detected: skill name "${skillName}" escapes s
Error message
Path traversal detected: skill name "${skillName}" escapes skills directory What it means
skillDir() resolves a skill name under `<storageDir>/skills` and throws if the resolved directory escapes that skills base directory. Skill names become directory names, so traversal sequences in a skill name are rejected.
Source
Thrown at packages/core/src/storage/filesystem-db.ts:205
const data = this.readDomain(filename);
if (id in data) {
delete data[id];
this.writeDomain(filename, data);
}
}
// =========================================================================
// Skills directory operations (real file tree, not JSON)
// =========================================================================
/**
* Get the path to a skill's directory.
*/
skillDir(skillName: string): string {
const skillsBase = join(this.dir, 'skills');
const dir = resolve(skillsBase, skillName);
if (!dir.startsWith(skillsBase + sep) && dir !== skillsBase) {
throw new Error(`Path traversal detected: skill name "${skillName}" escapes skills directory`);
}
return dir;
}
/**
* Resolve a file path within a skill directory, throwing if it escapes.
*/
private safeSkillPath(skillName: string, relativePath: string): string {
const base = this.skillDir(skillName);
const resolved = resolve(base, relativePath);
if (!resolved.startsWith(base + sep) && resolved !== base) {
throw new Error(`Path traversal detected: "${relativePath}" escapes skill directory`);
}
return resolved;
}
/**
* List all files in a skill's directory, returning relative paths.View on GitHub (pinned to 75dd419e61)
Solutions
- Sanitize the skill name: replace path separators and reject `..` segments before using it.
- Slugify external names (e.g. 'owner/repo' -> 'owner-repo') before storage.
- Validate against a pattern like /^[a-zA-Z0-9-_]+$/ before calling skillDir.
- Check where the skill name originates (user upload, registry) and enforce naming rules at ingestion.
Example fix
// before
const dir = fsDb.skillDir('../../malicious'); // throws
// after
const safeName = skillName.replace(/[^a-zA-Z0-9-_]/g, '-');
const dir = fsDb.skillDir(safeName); Defensive patterns
Strategy: validation
Validate before calling
function isSafeSkillName(name) {
return typeof name === 'string' && /^[a-zA-Z0-9][a-zA-Z0-9-_]*$/.test(name);
}
if (!isSafeSkillName(skillName)) throw new Error('invalid skill name'); Try / catch
try {
const dir = db.skillDir(skillName);
} catch (e) {
if (e.message.startsWith('Path traversal detected')) {
throw new Error(`Skill name not allowed: ${skillName}`);
}
throw e;
} Prevention
- Slugify names from external sources (registries, git refs) before storage.
- Enforce skill-name validation at ingestion/upload time.
- Reject names containing '/', '\\', or '..' early.
- Add unit tests covering traversal attempts against skillDir.
When it happens
Trigger: Calling skillDir (directly or via base/dir helpers) with a skill name containing `..`, `/`, `\`, or an absolute path.
Common situations: Skill names derived from user input, git repo/branch names, or external registries containing slashes (e.g. 'owner/repo') used unmodified as a directory name.
Related errors
- ${label} escapes workspace
- Path is outside the browsable root
- Path escapes workspace
- Path is outside the workspace
- Root escapes workspace
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/e6840efd02a80bc9.
Report an issue: GitHub.