{"record":{"id":"bb7b263cc120fede","repo":"stablyai/orca","slug":"refusing-to-place-the-disposable-validation-root-i","errorCode":null,"errorMessage":"Refusing to place the disposable validation root inside the primary home (${primaryHome}). Pass --temp-parent <dir> or set ORCA_CODEX_VALIDATION_TEMP_PARENT to a directory outside it.","messagePattern":"Refusing to place the disposable validation root inside the primary home \\((.+?)\\)\\. Pass --temp-parent <dir> or set ORCA_CODEX_VALIDATION_TEMP_PARENT to a directory outside it\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"config/scripts/run-codex-real-account-validation.mjs","lineNumber":101,"sourceCode":"    ORCA_USER_DATA_PATH: layout.userDataDir\n  }\n}\n\nexport async function createValidationLayout(options = {}) {\n  const primaryHome = path.resolve(options.primaryHome ?? os.homedir())\n  const envTempParent = process.env.ORCA_CODEX_VALIDATION_TEMP_PARENT?.trim()\n  const tempParent = path.resolve(options.tempParent ?? (envTempParent || os.tmpdir()))\n  // Why: guards must compare canonical paths — a symlinked temp parent must\n  // not smuggle the disposable root inside the primary home.\n  const [primaryHomeReal, tempParentReal] = await Promise.all([\n    resolveRealPath(primaryHome),\n    resolveRealPath(tempParent)\n  ])\n  // Why: on Windows the default %TEMP% lives inside %USERPROFILE%, which the\n  // disposable-home guard below rightly refuses. Fail before creating anything\n  // and point at the overrides instead of aborting with an opaque guard error.\n  if (samePath(tempParentReal, primaryHomeReal) || isWithin(tempParentReal, primaryHomeReal)) {\n    throw new Error(\n      `Refusing to place the disposable validation root inside the primary home (${primaryHome}). ` +\n        'Pass --temp-parent <dir> or set ORCA_CODEX_VALIDATION_TEMP_PARENT to a directory outside it.'\n    )\n  }\n  const tempRoot = await mkdtemp(path.join(tempParent, 'orca-codex-real-'))\n  const homeDir = path.join(tempRoot, 'home')\n  const userDataDir = path.join(tempRoot, 'user-data')\n  await Promise.all([\n    mkdir(homeDir, { recursive: true, mode: 0o700 }),\n    mkdir(userDataDir, { recursive: true, mode: 0o700 })\n  ])\n  const homeDirReal = await resolveRealPath(homeDir)\n  if (samePath(primaryHomeReal, homeDirReal) || isWithin(homeDirReal, primaryHomeReal)) {\n    throw new Error('Refusing to place the disposable validation home inside the primary home')\n  }\n  return { primaryHome, tempRoot, homeDir, userDataDir }\n}\n","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/config/scripts/run-codex-real-account-validation.mjs#L83-L119","documentation":"Thrown by the Codex real-account validation harness when the disposable validation root would be placed inside (or identical to) the primary home directory. The guard resolves both paths via realpath to defeat symlink smuggling, then rejects if tempParent equals or is contained within primaryHome. This prevents the validation's throwaway HOME from polluting the user's real home. On Windows the default %TEMP% lives inside %USERPROFILE%, so the guard fires there unless overridden.","triggerScenarios":"Running on Windows without --temp-parent or ORCA_CODEX_VALIDATION_TEMP_PARENT (since %TEMP% is under %USERPROFILE%). Also fires if os.tmpdir() resolves inside the home on any platform, or if a custom tempParent is a subdirectory of the home.","commonSituations":"A Windows developer runs the harness for the first time; the default temp dir trips the guard. Or a symlinked temp parent resolves into the home after realpath.","solutions":["Pass --temp-parent <dir> pointing to a directory outside your home, e.g. --temp-parent /var/tmp on Linux or a drive root on Windows.","Set ORCA_CODEX_VALIDATION_TEMP_PARENT to an external directory."],"exampleFix":"// before (Windows: %TEMP% is under %USERPROFILE%)\nnode config/scripts/run-codex-real-account-validation.mjs\n// after\nnode config/scripts/run-codex-real-account-validation.mjs --temp-parent C:\\BuildTemp","handlingStrategy":"validation","validationCode":"const [primaryHomeReal, tempParentReal] = await Promise.all([\n  resolveRealPath(primaryHome), resolveRealPath(tempParent)\n])\nif (samePath(tempParentReal, primaryHomeReal) || isWithin(tempParentReal, primaryHomeReal)) {\n  throw new Error('tempParent must be outside the primary home')\n}","typeGuard":"function isOutsideHome(candidateReal, homeReal) {\n  return !samePath(candidateReal, homeReal) && !isWithin(candidateReal, homeReal)\n}","tryCatchPattern":null,"preventionTips":["On Windows, always pass --temp-parent or ORCA_CODEX_VALIDATION_TEMP_PARENT since %TEMP% lives under %USERPROFILE%.","Resolve both paths with realpath before comparing to defeat symlink-based smuggling.","Fail before creating any directories so partial state is never left behind."],"tags":["security","containment","validation","windows","home-isolation"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}