mastra-ai/mastra · error
Path traversal detected: directory "${directory}" escapes st
Error message
Path traversal detected: directory "${directory}" escapes storage directory What it means
listDomainFiles() resolves the requested directory against the DB root and throws if the resolved path escapes that root. This guards filesystem-backed storage against path traversal (e.g. '../' sequences) reaching arbitrary directories.
Source
Thrown at packages/core/src/storage/filesystem-db.ts:107
mkdirSync(parentDir, { recursive: true });
}
writeFileSync(tmpPath, JSON.stringify(data, null, 2), 'utf-8');
renameSync(tmpPath, filePath);
}
/**
* Clear all data from a domain JSON file.
*/
clearDomain(filename: string): void {
this.writeDomain(filename, {});
}
listDomainFiles(directory: string, extension = '.json'): string[] {
const baseDir = resolve(this.dir, directory);
const rootDir = resolve(this.dir);
if (!baseDir.startsWith(rootDir + sep) && baseDir !== rootDir) {
throw new Error(`Path traversal detected: directory "${directory}" escapes storage directory`);
}
if (!existsSync(baseDir)) return [];
if (!statSync(baseDir).isDirectory()) {
throw new Error(`Configured domain path "${directory}" is a file, expected a directory`);
}
return readdirSync(baseDir)
.filter(file => extname(file) === extension && statSync(join(baseDir, file)).isFile())
.map(file => `${directory}/${file}`);
}
/**
* Check whether a domain file currently exists on disk.
*/
domainFileExists(filename: string): boolean {
const filePath = resolve(this.dir, filename);
const rootDir = resolve(this.dir);
if (!filePath.startsWith(rootDir + sep) && filePath !== rootDir) {View on GitHub (pinned to 75dd419e61)
Solutions
- Sanitize/normalize the directory argument before calling (strip `..`, path separators, or allowlist known domain names).
- Pass static, hardcoded subdirectory names for known domains.
- If input is user-driven, validate against a allowlist pattern (e.g. /^[a-zA-Z0-9-_]+$/) first.
- Check the storage `dir` configuration for unexpected relative-path composition.
Example fix
// before
const files = db.listDomainFiles(userInput); // '../../etc' -> throws
// after
const domain = userInput.replace(/[^a-zA-Z0-9-_]/g, '');
if (!domain) throw new Error('invalid domain directory');
const files = db.listDomainFiles(domain); Defensive patterns
Strategy: validation
Validate before calling
const path = require('path');
function isSafeDirName(dir) {
if (typeof dir !== 'string' || dir.length === 0) return false;
if (path.isAbsolute(dir)) return false;
const norm = path.normalize(dir);
return !norm.split(path.sep).includes('..');
} Try / catch
try {
const files = db.listDomainFiles(dir);
} catch (e) {
if (e.message.startsWith('Path traversal detected')) {
throw new Error(`Rejected unsafe storage directory: ${dir}`);
}
throw e;
} Prevention
- Never pass user-supplied strings directly as domain directories.
- Allowlist known domain directory names.
- Normalize paths before passing them to storage APIs.
- Sanitize IDs used to build directory names.
When it happens
Trigger: Calling listDomainFiles with a directory containing `..`, an absolute path, or any segment that resolves outside the storage root (`this.dir`).
Common situations: User- or request-supplied directory names passed straight into storage APIs; concatenating untrusted input into paths; misconfigured storage dir interacting with relative paths.
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/b0f96bbe16c1aeb3.
Report an issue: GitHub.