mastra-ai/mastra · error
Path traversal detected: "${relativePath}" escapes skill dir
Error message
Path traversal detected: "${relativePath}" escapes skill directory What it means
safeSkillPath() resolves a relative path within a skill's directory (after skillDir's own check) and throws if the result escapes that skill directory. It prevents file operations targeting other skills or arbitrary paths via `../` in the relative path.
Source
Thrown at packages/core/src/storage/filesystem-db.ts:217
* 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.
*/
listSkillFiles(skillName: string): string[] {
const dir = this.skillDir(skillName);
if (!existsSync(dir)) return [];
return walkDir(dir).map(abs => relative(dir, abs).split(sep).join('/'));
}
/**
* Read a file from a skill's directory.
*/
readSkillFile(skillName: string, relativePath: string): Buffer | null {
const filePath = this.safeSkillPath(skillName, relativePath);View on GitHub (pinned to 75dd419e61)
Solutions
- Sanitize/normalize the relative path: reject absolute paths and any `..` segment before calling.
- Iterate only over file lists produced by the library (listSkillFiles) rather than untrusted manifests.
- Validate entries against /^[a-zA-Z0-9-_/.]+$/ and require the normalized path to stay within the skill dir.
- When importing skills, validate the archive contents before writing (reject entries escaping the skill root).
Example fix
// before
const p = db.filePath(skillName, entry.name); // entry may be '../../x'
// after
const safeRel = entry.name.replace(/^(\.\.?(\/|\\))+/, '').replace(/[^a-zA-Z0-9-_.\/]/g, '');
if (safeRel.includes('..')) throw new Error('unsafe skill file path');
const p = db.filePath(skillName, safeRel); Defensive patterns
Strategy: validation
Validate before calling
const path = require('path');
function isSafeSkillRelPath(rel) {
if (typeof rel !== 'string' || rel.length === 0) return false;
if (path.isAbsolute(rel)) return false;
const norm = path.normalize(rel);
return !norm.split(path.sep).includes('..');
} Try / catch
try {
const p = db.filePath(skillName, rel);
} catch (e) {
if (e.message.startsWith('Path traversal detected')) {
throw new Error(`Rejected skill file path: ${rel}`);
}
throw e;
} Prevention
- Only trust file lists produced by the library's own listing APIs.
- Validate entries in untrusted skill archives (zip-slip protection) before use.
- Reject absolute paths and `..` segments in relative paths.
- Keep skill content imports sandboxed to the skill directory.
When it happens
Trigger: Calling filePath (which delegates to safeSkillPath) with a relativePath containing `..`, absolute paths, or leading separators that resolve outside the skill directory.
Common situations: Skill file lists from untrusted archives/registries containing entries like '../../package.json'; user-specified file names within a skill editor; ZIP-slip style extracted entries.
Related errors
- Path traversal detected: skill name "${skillName}" escapes s
- Invalid ${label} path: ${input}
- Invalid file path "${filePath}". Absolute paths are not allo
- Invalid file path "${filePath}". Path traversal is not allow
- Invalid route path: "${path}". Path cannot contain '..', '?'
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/97b1768ed4cb7c34.
Report an issue: GitHub.