{"record":{"id":"c4496c1c460e838f","repo":"google-gemini/gemini-cli","slug":"security-violation-the-path-trimmedpath-is-o","errorCode":null,"errorMessage":"Security violation: The path \"${trimmedPath}\" is outside the allowed root directory.","messagePattern":"Security violation: The path \"(.+?)\" is outside the allowed root directory\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"packages/a2a-server/src/utils/path_utils.ts","lineNumber":45,"sourceCode":"\n  if (trimmedPath.includes('\\0')) {\n    throw new Error('Security violation: Null byte detected in path.');\n  }\n\n  try {\n    const canonicalAllowedRoot = resolveToRealPath(allowedRoot);\n    const resolvedWorkspacePath = path.resolve(\n      canonicalAllowedRoot,\n      trimmedPath,\n    );\n    const canonicalWorkspacePath = resolveToRealPath(resolvedWorkspacePath);\n\n    // Check if the resolved path is within the allowed root directory\n    if (\n      canonicalWorkspacePath !== canonicalAllowedRoot &&\n      !isSubpath(canonicalAllowedRoot, canonicalWorkspacePath)\n    ) {\n      throw new Error(\n        `Security violation: The path \"${trimmedPath}\" is outside the allowed root directory.`,\n      );\n    }\n\n    const stats = await fs.promises.stat(canonicalWorkspacePath);\n    if (!stats.isDirectory()) {\n      throw new Error(`The path \"${trimmedPath}\" is not a directory.`);\n    }\n\n    return canonicalWorkspacePath;\n  } catch (e) {\n    if (e instanceof Error && 'code' in e && e.code === 'ENOENT') {\n      throw new Error(`The path \"${trimmedPath}\" does not exist.`);\n    }\n    throw e; // Re-throw other errors\n  }\n}\n","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/google-gemini/gemini-cli/blob/5024443c7217464a66e98f80d73172a26440bd8f/packages/a2a-server/src/utils/path_utils.ts#L27-L63","documentation":"After resolving both the allowed root and the workspace path to their canonical (real, symlink-resolved) filesystem paths, the function checks containment. If the workspace path is neither identical to the root nor a strict subdirectory of it, it throws to prevent access outside the sandboxed root.","triggerScenarios":"Passing a relative path with ../ sequences that escape the root (e.g., validateWorkspacePath('../../etc', '/home/user/project')), or an absolute path pointing outside the root, or a path that resolves through a symlink to a location outside the allowed root.","commonSituations":"Symlinks within the workspace that point outside it; relative paths with excessive parent directory traversals; user-supplied paths not validated upstream; incorrect allowedRoot default (process.cwd() is not what was expected).","solutions":["Ensure the workspace path is relative and stays within the root without ../ escapes.","Resolve symlinks before calling the function to understand the real filesystem target.","Only use paths returned by trusted discovery mechanisms within the workspace.","Verify that process.cwd() (the default allowedRoot) is set to the intended sandbox root."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import { resolveToRealPath, isSubpath } from '@google/gemini-cli-core';\nimport * as path from 'node:path';\n\nfunction isWithinRoot(candidate: string, root: string): boolean {\n  const canonicalRoot = resolveToRealPath(root);\n  const canonicalCandidate = resolveToRealPath(path.resolve(canonicalRoot, candidate));\n  return canonicalCandidate === canonicalRoot || isSubpath(canonicalRoot, canonicalCandidate);\n}\n\n// Before calling validateWorkspacePath:\nif (!isWithinRoot(userPath, allowedRoot)) {\n  throw new Error('Path escapes the allowed root');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only use relative paths returned by trusted in-workspace discovery mechanisms.","Resolve and inspect symlinks before treating a path as workspace-relative.","Set the allowedRoot explicitly rather than relying on process.cwd() defaults.","Reject any user input containing '..' segments at the input boundary."],"tags":["security","path-traversal","validation","sandbox"],"backgroundTag":null,"analyzedSha":"5024443c7217464a66e98f80d73172a26440bd8f","analyzedAt":"2026-08-12T06:01:53.711Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}