mastra-ai/mastra · error
Path traversal detected: file "${filename}" escapes storage
Error message
Path traversal detected: file "${filename}" escapes storage directory What it means
domainFileExists() resolves the given filename against the storage root and throws if the resolved path escapes that root. It prevents probing for files outside the storage directory via traversal sequences.
Source
Thrown at packages/core/src/storage/filesystem-db.ts:126
}
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) {
throw new Error(`Path traversal detected: file "${filename}" escapes storage directory`);
}
return existsSync(filePath);
}
removeDomainFile(filename: string): void {
this.cache.delete(filename);
const filePath = resolve(this.dir, filename);
const rootDir = resolve(this.dir);
if (!filePath.startsWith(rootDir + sep) && filePath !== rootDir) {
throw new Error(`Path traversal detected: file "${filename}" escapes storage directory`);
}
if (existsSync(filePath)) {
rmSync(filePath);
}
}
/**
* Invalidate the in-memory cache for a domain, forcing a re-read from disk on next access.View on GitHub (pinned to 75dd419e61)
Solutions
- Sanitize the filename before calling (strip path separators and `..`; derive from a allowlisted ID).
- Use library APIs that generate filenames internally (e.g. per-entity helpers) rather than hand-built strings.
- Validate IDs used in filenames against a strict pattern before composing paths.
- Log the offending filename to identify which caller is passing unsafe values.
Example fix
// before
const exists = db.domainFileExists(`../../${id}.json`); // throws
// after
const safeName = `${String(id).replace(/[^a-zA-Z0-9-_]/g, '')}.json`;
const exists = db.domainFileExists(safeName); Defensive patterns
Strategy: validation
Validate before calling
const path = require('path');
function isSafeFileName(name) {
if (typeof name !== 'string' || name.length === 0) return false;
if (path.isAbsolute(name)) return false;
const norm = path.normalize(name);
return !norm.split(path.sep).includes('..') && !norm.includes('/') && !norm.includes('\\');
} Try / catch
try {
return db.domainFileExists(name);
} catch (e) {
if (e.message.startsWith('Path traversal detected')) {
return false; // treat unsafe names as nonexistent, and log
}
throw e;
} Prevention
- Sanitize or encode entity IDs before embedding them in filenames.
- Derive filenames from library helpers rather than string concatenation.
- Reject IDs containing slashes or `..` at ingestion time.
- Log rejected filenames to find the caller passing unsafe input.
When it happens
Trigger: Calling domainFileExists (directly or via sharedFileExists) with a filename containing `..`, an absolute path, or otherwise resolving outside `this.dir`.
Common situations: Passing untrusted/user-supplied filenames or keys into existence checks; building filenames by concatenating external IDs without sanitization.
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/5fd4b0f36043801c.
Report an issue: GitHub.