{"record":{"id":"0bea1289cab6fb1a","repo":"n8n-io/n8n","slug":"access-denied-cannot-access-relativepath","errorCode":null,"errorMessage":"Access denied: cannot access \"${relativePath}\"","messagePattern":"Access denied: cannot access \"(.+?)\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/computer-use/src/tools/filesystem/fs-utils.ts","lineNumber":250,"sourceCode":"\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// lstat also failed — the path truly does not exist.\n\t\t\t}\n\n\t\t\t// Path does not exist and is not a symlink; append remaining parts as-is.\n\t\t\tcurrent = path.join(current, ...parts.slice(i));\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (!current.startsWith(realBase + path.sep) && current !== realBase) {\n\t\tthrow new Error(`Path \"${relativePath}\" escapes the base directory`);\n\t}\n\n\t// Check if the resolved real path targets a protected path (e.g. settings directory).\n\t// This catches symlink-based bypasses since `current` has all symlinks resolved.\n\tif (isProtectedSettingsPath(current)) {\n\t\tthrow new Error(`Access denied: cannot access \"${relativePath}\"`);\n\t}\n\n\treturn { absolutePath: absolute, realBasePath: realBase, resolvedPath: current };\n}\n\nexport async function resolveSafePath(basePath: string, relativePath: string): Promise<string> {\n\tconst { absolutePath } = await resolveSafePathDetails(basePath, relativePath);\n\treturn absolutePath;\n}\n\nexport async function resolveReadablePath(basePath: string, relativePath: string): Promise<string> {\n\tconst { absolutePath, realBasePath, resolvedPath } = await resolveSafePathDetails(\n\t\tbasePath,\n\t\trelativePath,\n\t);\n\tassertNoExcludedSegments(absolutePath, basePath);\n\tassertNoExcludedSegments(resolvedPath, realBasePath);\n\treturn absolutePath;","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/computer-use/src/tools/filesystem/fs-utils.ts#L232-L268","documentation":"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.","triggerScenarios":"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.","commonSituations":"Malicious or accidental symlink that would expose n8n's internal configuration, encryption keys, or settings files through the filesystem tools.","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"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import { isProtectedSettingsPath } from '../config';\n\nasync function isSafeToAccess(realPath: string): Promise<boolean> {\n  return !isProtectedSettingsPath(realPath);\n}","typeGuard":"function isProtectedPathError(e: unknown): boolean {\n  return e instanceof Error && e.message.startsWith('Access denied: cannot access');\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["filesystem","security","computer-use"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}