{"record":{"id":"4081be85c9d64612","repo":"affaan-m/ECC","slug":"refusing-to-record-a-legacy-sync-path-outside-trus","errorCode":null,"errorMessage":"Refusing to record a legacy sync path outside trusted roots: ${filePath}","messagePattern":"Refusing to record a legacy sync path outside trusted roots: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/codex-legacy-sync.js","lineNumber":279,"sourceCode":"    paths: [],\n    rollbackPaths: [],\n  };\n\n  for (const [key, filePath] of [['config', configPath], ['agents', agentsPath]]) {\n    if (priorState) break;\n    const snapshot = readRegularFileNoFollow(filePath, 'utf8');\n    state.before[key] = snapshot ? snapshot.content : null;\n  }\n  atomicWriteJson(statePath, state);\n  return statePath;\n}\n\nfunction recordLegacySyncPath(options) {\n  const state = readState(options.statePath);\n  const filePath = path.resolve(options.filePath);\n  const trustedRoot = getTrustedRoot(state, filePath);\n  if (!trustedRoot) {\n    throw new Error(`Refusing to record a legacy sync path outside trusted roots: ${filePath}`);\n  }\n  if (hasUnsafeManagedAncestor(filePath, trustedRoot)) {\n    throw new Error(`Refusing to manage legacy sync path through symlinked ancestor: ${filePath}`);\n  }\n  if (!state.paths.some(entry => entry.path === filePath)) {\n    const snapshot = snapshotLegacyPath(filePath);\n    state.paths.push(snapshot);\n    state.rollbackPaths = [...(state.rollbackPaths || []), { ...snapshot }];\n    atomicWriteJson(options.statePath, state);\n  }\n}\n\nfunction rollbackLegacyCodexSync(options) {\n  const state = readState(options.statePath);\n  const restoredPaths = [];\n  const retainedPaths = [];\n\n  const rollbackPaths = Array.isArray(state.rollbackPaths) ? state.rollbackPaths : state.paths;","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/codex-legacy-sync.js#L261-L297","documentation":"recordLegacySyncPath refuses to register a file path in the legacy sync state unless that path resolves under one of the trusted roots recorded in the sync state. This is a safety guard so the tool never records or later mutates files outside directories it has been explicitly allowed to manage.","triggerScenarios":"Calling recordLegacySyncPath({ statePath, filePath }) where path.resolve(filePath) is not inside any trusted root returned by getTrustedRoot(state, filePath) — trusted roots are seeded from codexHome plus prior state's trustedRoots/installedHooksPath.","commonSituations":"Passing an absolute path in a different directory tree than the Codex home; a path whose symlink resolution escapes the trusted root; passing a repo file path while only codexHome is trusted.","solutions":["Check that the filePath you pass is inside the Codex home or another trusted root recorded in the state file","Add the parent directory to trustedRoots by starting sync from that root (beginLegacySyncState accumulates trusted roots)","Resolve symlinks in your path (fs.realpathSync) before calling, so it lands inside a trusted root","Verify the state file's trustedRoots array includes the intended directory"],"exampleFix":"// before\nrecordLegacySyncPath({ statePath, filePath: '/some/other/place/config.toml' })\n// after\nconst real = require('fs').realpathSync('/some/other/place/config.toml');\n// ensure 'real' is under codexHome or a trusted root, then:\nrecordLegacySyncPath({ statePath, filePath: real });","handlingStrategy":"validation","validationCode":"const filePath = path.resolve(candidate);\nconst state = readState(statePath);\nif (!getTrustedRoot(state, filePath)) throw new Error('path not under trusted roots: ' + filePath);","typeGuard":"const isUnderRoot = (p, root) => path.resolve(p).startsWith(path.resolve(root) + path.sep);","tryCatchPattern":"try { recordLegacySyncPath(opts); } catch (e) {\n  if (String(e.message).includes('outside trusted roots')) console.error('Add', path.dirname(opts.filePath), 'to trusted roots first');\n  else throw e;\n}","preventionTips":["Record paths that live inside codexHome or another trusted root","Resolve symlinks with fs.realpathSync before recording","Seed trustedRoots via beginLegacySyncState for every extra directory you manage","Never record ad-hoc temp paths"],"tags":["security","path-validation","sync"],"backgroundTag":"path-traversal-blocked","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}