{"record":{"id":"e08d2985b0d3ecd8","repo":"google-gemini/gemini-cli","slug":"workspace-path-resolvedpath-is-outside-the-allo","errorCode":null,"errorMessage":"Workspace path ${resolvedPath} is outside the allowed root directory","messagePattern":"Workspace path (.+?) is outside the allowed root directory","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/a2a-server/src/config/config.ts","lineNumber":469,"sourceCode":"        );\n      } else {\n        throw err;\n      }\n    }\n\n    const isTestEnv =\n      process.env['VITEST'] === 'true' ||\n      process.env['NODE_ENV'] === 'test' ||\n      process.argv.some((arg) => arg.includes('vitest')) ||\n      resolvedPath.startsWith(resolveToRealPath(tmpdir()));\n\n    const allowedRoot = resolveToRealPath(\n      getEnv('CODER_AGENT_ALLOWED_ROOT') ||\n        (isTestEnv ? path.parse(resolvedPath).root : homedir()),\n    );\n    const relative = path.relative(allowedRoot, resolvedPath);\n    if (relative.startsWith('..') || path.isAbsolute(relative)) {\n      throw new Error(\n        `Workspace path ${resolvedPath} is outside the allowed root directory`,\n      );\n    }\n\n    let stats: fs.Stats;\n    try {\n      stats = await fs.promises.stat(resolvedPath);\n    } catch (err: unknown) {\n      if (\n        err &&\n        typeof err === 'object' &&\n        'code' in err &&\n        err.code === 'ENOENT'\n      ) {\n        if (isTestEnv) {\n          await fs.promises.mkdir(resolvedPath, { recursive: true });\n          stats = await fs.promises.stat(resolvedPath);\n        } else {","sourceCodeStart":451,"sourceCodeEnd":487,"githubUrl":"https://github.com/google-gemini/gemini-cli/blob/5024443c7217464a66e98f80d73172a26440bd8f/packages/a2a-server/src/config/config.ts#L451-L487","documentation":"Thrown by validateWorkspacePath when the resolved workspace path does not lie under the allowed root. The allowed root is CODER_AGENT_ALLOWED_ROOT if set, otherwise homedir() in production (or the filesystem root / the tmpdir in test environments). path.relative(allowedRoot, resolvedPath) starting with '..' or being absolute means the workspace escaped the sandbox.","triggerScenarios":"CODER_AGENT_WORKSPACE_PATH resolves to a directory outside the user's home and CODER_AGENT_ALLOWED_ROOT is unset; symlink resolution (resolveToRealPath) dereferences a workspace symlink to a path outside the allowed root; allowed root misconfigured to a parent that doesn't contain the workspace.","commonSituations":"CI runner whose home is /root but the checkout lives in /workspace; Docker container where the workspace is mounted outside the default home; developer pointing at /tmp/myproj without setting CODER_AGENT_ALLOWED_ROOT in non-test mode.","solutions":["Set CODER_AGENT_ALLOWED_ROOT to a directory that contains the workspace (e.g. the repo root or /).","Move the workspace under the user's home directory.","If using symlinks, ensure the link target is within the allowed root.","In test/CI, confirm NODE_ENV=test or VITEST=true is set so the test-env branch (root allowed root) applies."],"exampleFix":"# before\nexport CODER_AGENT_WORKSPACE_PATH=/workspace/myproj\n# throws: outside allowed root (default homedir)\n\n# after\nexport CODER_AGENT_ALLOWED_ROOT=/workspace\nexport CODER_AGENT_WORKSPACE_PATH=/workspace/myproj","handlingStrategy":"validation","validationCode":"import path from 'node:path';\nimport { homedir } from 'node:os';\n\nfunction assertWorkspaceAllowed(workspace: string) {\n  const root = process.env['CODER_AGENT_ALLOWED_ROOT'] || homedir();\n  const rel = path.relative(root, path.resolve(workspace));\n  if (rel.startsWith('..') || path.isAbsolute(rel)) {\n    throw new Error(`Workspace ${workspace} outside allowed root ${root}. Set CODER_AGENT_ALLOWED_ROOT.`);\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set CODER_AGENT_ALLOWED_ROOT explicitly in any non-home deployment (CI, containers).","Resolve symlinks before comparing - resolveToRealPath dereferences, so test the real target.","In tests, ensure NODE_ENV=test or VITEST=true so the test-env branch (root allowed root) applies.","Document the allowed-root contract in your deploy runbook."],"tags":["workspace","sandbox","security","config","path-validation"],"backgroundTag":null,"analyzedSha":"5024443c7217464a66e98f80d73172a26440bd8f","analyzedAt":"2026-08-12T06:01:53.711Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}