{"record":{"id":"80d64fd7a6df473d","repo":"Yeachan-Heo/oh-my-codex","slug":"state-directory-escapes-the-authorized-run-directo","errorCode":null,"errorMessage":"state directory escapes the authorized run directory","messagePattern":"state directory escapes the authorized run directory","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"src/cli/index.ts","lineNumber":8151,"sourceCode":"  for (const file of files) {\n    if (!file.endsWith(\".json\")) continue;\n    const record = readMadmaxDetachedActiveRecord(join(activeDir, file));\n    if (!record || file !== `${record.context_key}.json`) continue;\n    if (!record.session_id || normalizeSessionId(record.session_id) !== record.session_id) continue;\n    if (!hasMatchingMadmaxDetachedRuntimeBinding(record)) continue;\n    if (\n      canonicalizePathForRunDirMatch(record.source_cwd) !== canonicalCwd\n      && (!record.worktree_cwd || canonicalizePathForRunDirMatch(record.worktree_cwd) !== canonicalCwd)\n    ) continue;\n\n    try {\n      const canonicalRunDir = realpathSync(resolve(record.run_dir));\n      if (!isCanonicalPathWithin(canonicalRunsRoot, canonicalRunDir)) {\n        throw new Error(\"run directory escapes the authorized runs root\");\n      }\n      const stateDir = realpathSync(join(canonicalRunDir, \".omx\", \"state\"));\n      if (!isCanonicalPathWithin(canonicalRunDir, stateDir)) {\n        throw new Error(\"state directory escapes the authorized run directory\");\n      }\n      const session = JSON.parse(await readFile(join(stateDir, \"session.json\"), \"utf-8\")) as Record<string, unknown>;\n      if (session.session_id !== record.session_id) throw new Error(\"run session pointer changed\");\n      const sessionDir = realpathSync(join(stateDir, \"sessions\", record.session_id));\n      if (!isCanonicalPathWithin(stateDir, sessionDir)) {\n        throw new Error(\"session directory escapes the authorized state directory\");\n      }\n      candidates.push({ sessionDir, sessionId: record.session_id, record });\n    } catch (err) {\n      throw new Error(`Refusing cancellation because detached run authority is invalid: ${record.run_dir}.`, { cause: err });\n    }\n  }\n\n  if (candidates.length > 1) throw new Error(\"Refusing cancellation because multiple detached run authorities match.\");\n  if (candidates.length === 0) return null;\n  const [{ sessionDir, sessionId, record }] = candidates;\n  const refs: ModeStateFileRef[] = [];\n  const stateFiles = await readdir(sessionDir).catch(() => [] as string[]);","sourceCodeStart":8133,"sourceCodeEnd":8169,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/cli/index.ts#L8133-L8169","documentation":"The .omx/state directory inside the canonicalized run dir resolves (after realpath) outside that run dir, typically because a path component is a symlink; the code refuses to operate on it.","triggerScenarios":"realpathSync(join(canonicalRunDir, '.omx', 'state')) lands outside canonicalRunDir — e.g. .omx or state is a symlink to another location.","commonSituations":"Users symlinking .omx to shared storage or another project; malicious or accidental tampering with the state dir.","solutions":["Remove the symlink at <run_dir>/.omx/state (and .omx if needed) so the state dir is a real directory inside the run dir","Restore state from the proper location or re-launch the session to recreate state","Avoid symlinking .omx internals; keep run dirs self-contained"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const state = realpathSync(join(runDir, '.omx', 'state'));\nif (!state.startsWith(realpathSync(runDir) + sep)) throw new Error('.omx/state must live inside run dir');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Don't symlink .omx or .omx/state","Keep run dirs self-contained on one filesystem","Audit for tampering if this fires unexpectedly"],"tags":["path-traversal","security","symlink"],"backgroundTag":"path-escapes-allowed-root","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}