modelcontextprotocol/servers · error · Error
Access denied - path outside allowed directories: ${absolute
Error message
Access denied - path outside allowed directories: ${absolute} not in ${allowedDirectories.join(', ')} What it means
Thrown by `validatePath` in the filesystem server when the normalized requested path does not lie within any allowed directory. This is the primary security boundary: every file operation runs through `validatePath`, which checks the resolved absolute path before any I/O. Symlink resolution is then applied separately (error 17).
Source
Thrown at src/filesystem/lib.ts:110
// If no valid resolution found, use the first allowed directory as base
// This provides a consistent fallback behavior
return path.resolve(allowedDirectories[0], relativePath);
}
// Security & Validation Functions
export async function validatePath(requestedPath: string): Promise<string> {
const expandedPath = expandHome(requestedPath);
const absolute = path.isAbsolute(expandedPath)
? path.resolve(expandedPath)
: resolveRelativePathAgainstAllowedDirectories(expandedPath);
const normalizedRequested = normalizePath(absolute);
// Security: Check if path is within allowed directories before any file operations
const isAllowed = isPathWithinAllowedDirectories(normalizedRequested, allowedDirectories);
if (!isAllowed) {
throw new Error(`Access denied - path outside allowed directories: ${absolute} not in ${allowedDirectories.join(', ')}`);
}
// Security: Handle symlinks by checking their real path to prevent symlink attacks
// This prevents attackers from creating symlinks that point outside allowed directories
try {
const realPath = await fs.realpath(absolute);
const normalizedReal = normalizePath(realPath);
if (!isPathWithinAllowedDirectories(normalizedReal, allowedDirectories)) {
throw new Error(`Access denied - symlink target outside allowed directories: ${realPath} not in ${allowedDirectories.join(', ')}`);
}
return realPath;
} catch (error) {
// Security: For new files that don't exist yet, verify parent directory
// This ensures we can't create files in unauthorized locations
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
const parentDir = path.dirname(absolute);
try {
const realParentPath = await fs.realpath(parentDir);View on GitHub (pinned to 76d64c822f)
Solutions
- Request a path inside one of the allowed directories shown in the error message.
- Add the needed directory to the server's allowed directories (CLI args or client roots).
- Avoid `..` segments; resolve and normalize the path client-side before sending.
Example fix
# before (only /home/me/projects allowed)
read_text_file({ path: '/etc/passwd' })
# after
read_text_file({ path: '/home/me/projects/notes.txt' }) Defensive patterns
Strategy: validation
Validate before calling
import path from 'node:path';
function isWithinAllowed(p: string, allowed: string[]): boolean {
const a = path.resolve(p);
return allowed.some(d => a === path.resolve(d) || a.startsWith(path.resolve(d) + path.sep));
}
if (!isWithinAllowed(args.path, allowedDirs)) { /* surface error */ } Try / catch
try {
await readFile({ path });
} catch (e) {
if (e instanceof Error && e.message.startsWith('Access denied - path outside')) {
// path resolves outside allowlist; choose an allowed path or extend allowlist
}
} Prevention
- Only request paths inside the configured allowed directories.
- Avoid '..' traversal; normalize paths client-side first.
- Extend the allowlist (CLI or roots) when legitimate access is needed.
When it happens
Trigger: Any filesystem tool call (`read_text_file`, `write_file`, `list_directory`, etc.) whose `path` resolves outside all configured allowed directories — e.g. requesting `/etc/passwd` when only `/home/me/projects` is allowed, or a relative path that escapes via `..`.
Common situations: Clients passing absolute paths outside the allowlist, `..` traversal in relative paths, home shorthand (`~/`) expanding outside the allowlist, or a misconfigured allowlist that omits the needed directory.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Access denied - parent directory outside allowed directories
- Access denied - symlink target outside allowed directories:
- Unsupported URL protocol for ${dataUri}. Only http, https, a
- Domain ${domain} is not in the allowed domains list.
- Cannot specify both head and tail parameters simultaneously
AI-assisted analysis of modelcontextprotocol/servers@76d64c822f (2026-08-12).
Data as JSON: /api/errors/3b6858d8b566c5a5.
Report an issue: GitHub.