{"record":{"id":"729782da75dd8bd8","repo":"Mintplex-Labs/anything-llm","slug":"access-denied-symlink-target-outside-allowed-dir","errorCode":null,"errorMessage":"Access denied - symlink target outside allowed directories.","messagePattern":"Access denied - symlink target outside allowed directories\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/utils/agents/aibitat/plugins/filesystem/lib.js","lineNumber":444,"sourceCode":"      console.log(\n        `[validatePath] Access denied - path outside allowed directories: ${absolute} not in ${this.#allowedDirectories.join(\", \")}`\n      );\n      throw new Error(`Access denied - path outside allowed directories.`);\n    }\n\n    try {\n      const realPath = await fs.realpath(absolute);\n      const normalizedReal = this.#normalizePath(realPath);\n      if (\n        !this.#isPathWithinAllowedDirectories(\n          normalizedReal,\n          this.#allowedDirectories\n        )\n      ) {\n        console.log(\n          `[validatePath] Access denied - symlink target outside allowed directories: ${realPath} not in ${this.#allowedDirectories.join(\", \")}`\n        );\n        throw new Error(\n          `Access denied - symlink target outside allowed directories.`\n        );\n      }\n      return realPath;\n    } catch (error) {\n      if (error.code === \"ENOENT\") {\n        const parentDir = path.dirname(absolute);\n        try {\n          const realParentPath = await fs.realpath(parentDir);\n          const normalizedParent = this.#normalizePath(realParentPath);\n          if (\n            !this.#isPathWithinAllowedDirectories(\n              normalizedParent,\n              this.#allowedDirectories\n            )\n          ) {\n            console.log(\n              `[validatePath] Access denied - parent directory outside allowed directories: ${realParentPath} not in ${this.#allowedDirectories.join(\", \")}`","sourceCodeStart":426,"sourceCodeEnd":462,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/526360e320da9d1b36074be5ed64fe76e5bbfbbd/server/utils/agents/aibitat/plugins/filesystem/lib.js#L426-L462","documentation":"Thrown by validatePath() after fs.realpath() resolves the requested path to a real target that lies OUTSIDE the allowed directories. This catches symlink-escape attempts where the path itself appears inside the workspace but ultimately points elsewhere. Distinct from 394, which fires before realpath; this fires after, on the resolved target.","triggerScenarios":"A path inside the allowed workspace that is a symlink whose target resolves outside the workspace (e.g., workspace/secret -> /etc). The normalized requested path passes the first check, but realpath reveals the true destination is forbidden.","commonSituations":"A malicious or accidental symlink planted in the workspace pointing to system files; a symlink chain that eventually leaves the workspace; an agent or user creating a link to shortcut access to outside files.","solutions":["Remove or rewrite the offending symlink so its target is within an allowed directory.","Audit the workspace for symlinks pointing outside (find -type l).","Do not create symlinks in the workspace that escape the sandbox."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const fs = require(\"fs/promises\");\nasync function assertSymlinkTargetInside(p, allowedDirs) {\n  const st = await fs.lstat(p);\n  if (st.isSymbolicLink()) {\n    const target = await fs.realpath(p);\n    if (!allowedDirs.some((d) => target.startsWith(path.resolve(d))))\n      throw new Error(`Symlink ${p} escapes workspace`);\n  }\n}","typeGuard":null,"tryCatchPattern":"try { await filesystem.validatePath(p); }\ncatch (e) {\n  if (e.message.includes(\"symlink target outside\")) { /* remove the offending link */ }\n  else throw e;\n}","preventionTips":["Do not place symlinks in the workspace that point outside it.","Audit the workspace for escaping symlinks before filesystem operations.","Treat realpath-resolved targets as untrusted until confirmed inside the sandbox."],"tags":["filesystem","security","symlink","sandbox","path-validation"],"backgroundTag":null,"analyzedSha":"526360e320da9d1b36074be5ed64fe76e5bbfbbd","analyzedAt":"2026-08-13T01:45:47.170Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}