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

  1. Sanitize the skill name: replace path separators and reject `..` segments before using it.
  2. Slugify external names (e.g. 'owner/repo' -> 'owner-repo') before storage.
  3. Validate against a pattern like /^[a-zA-Z0-9-_]+$/ before calling skillDir.
  4. 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

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


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/e6840efd02a80bc9. Report an issue: GitHub.