n8n-io/n8n · error · Error
Access denied: cannot access "${relativePath}"
Error message
Access denied: cannot access "${relativePath}" What it means
Thrown by resolveSafePathDetails() when isProtectedSettingsPath() returns true for the fully resolved real path. This is a secondary security guard that runs after the base-directory containment check — it catches cases where a symlink resolves to a protected path (e.g. the n8n settings/config directory) even if that path is technically inside the base dir. The check uses the resolved real path, so symlink-based bypasses targeting n8n's internal configuration are caught.
Source
Thrown at packages/@n8n/computer-use/src/tools/filesystem/fs-utils.ts:250
}
} catch {
// lstat also failed — the path truly does not exist.
}
// Path does not exist and is not a symlink; append remaining parts as-is.
current = path.join(current, ...parts.slice(i));
break;
}
}
if (!current.startsWith(realBase + path.sep) && current !== realBase) {
throw new Error(`Path "${relativePath}" escapes the base directory`);
}
// Check if the resolved real path targets a protected path (e.g. settings directory).
// This catches symlink-based bypasses since `current` has all symlinks resolved.
if (isProtectedSettingsPath(current)) {
throw new Error(`Access denied: cannot access "${relativePath}"`);
}
return { absolutePath: absolute, realBasePath: realBase, resolvedPath: current };
}
export async function resolveSafePath(basePath: string, relativePath: string): Promise<string> {
const { absolutePath } = await resolveSafePathDetails(basePath, relativePath);
return absolutePath;
}
export async function resolveReadablePath(basePath: string, relativePath: string): Promise<string> {
const { absolutePath, realBasePath, resolvedPath } = await resolveSafePathDetails(
basePath,
relativePath,
);
assertNoExcludedSegments(absolutePath, basePath);
assertNoExcludedSegments(resolvedPath, realBasePath);
return absolutePath;View on GitHub (pinned to 5ac6606e81)
Solutions
- Remove the symlink that targets the protected settings path
- Access n8n settings through the n8n UI or REST API, not through filesystem tools
- Audit symlinks in the base directory for any that resolve to system or application config paths
Defensive patterns
Strategy: validation
Validate before calling
import { isProtectedSettingsPath } from '../config';
async function isSafeToAccess(realPath: string): Promise<boolean> {
return !isProtectedSettingsPath(realPath);
} Type guard
function isProtectedPathError(e: unknown): boolean {
return e instanceof Error && e.message.startsWith('Access denied: cannot access');
} Prevention
- Audit symlinks in the base directory for any that target n8n settings or config paths
- Access n8n settings through the UI or REST API, never through filesystem tools
- Check isProtectedSettingsPath on resolved real paths before tool access
When it happens
Trigger: A symlink inside the base directory points to the n8n settings or configuration directory, and a tool tries to read or write through that symlink. The real-path check after incremental symlink resolution detects the protected target.
Common situations: Malicious or accidental symlink that would expose n8n's internal configuration, encryption keys, or settings files through the filesystem tools.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Access denied: "${excludedSegment}" is excluded from filesys
- Path "${relativePath}" escapes the base directory
- Pattern "${pattern}" escapes the base directory
- Invalid skill at ${sourceDirectory}: ${errors.join('; ')}
- User permanently denied access to ${resource.toolGroup}: ${r
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/0bea1289cab6fb1a.
Report an issue: GitHub.