{"record":{"id":"6f5f2b0e5c36dc70","repo":"affaan-m/ECC","slug":"refusing-to-access-memory-through-symlink-director","errorCode":null,"errorMessage":"Refusing to access memory through symlink directory: ${directory}","messagePattern":"Refusing to access memory through symlink directory: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/memory-vault.js","lineNumber":119,"sourceCode":"  const root = roots[scope];\n  if (typeof root !== 'string' || root.length === 0) {\n    throw new Error(`No memory root is configured for scope \"${scope}\".`);\n  }\n  const boundary = roots[VAULT_ROOT_BOUNDARIES]?.[scope];\n  if (typeof boundary !== 'string' || boundary.length === 0) {\n    throw new Error(`No trusted boundary policy is configured for memory scope \"${scope}\".`);\n  }\n  assertWithinTrustedRoot(root, boundary, 'access memory through a symlink');\n  if (fs.existsSync(root) && fs.lstatSync(root).isSymbolicLink()) {\n    throw new Error(`Refusing to access memory through symlink root: ${root}`);\n  }\n  return root;\n}\n\nfunction assertMemoryDirectorySafe(directory, root) {\n  assertWithinTrustedRoot(directory, root, 'access memory directory');\n  if (fs.existsSync(directory) && fs.lstatSync(directory).isSymbolicLink()) {\n    throw new Error(`Refusing to access memory through symlink directory: ${directory}`);\n  }\n  return directory;\n}\n\nfunction sameFileIdentity(left, right) {\n  // The inode is the primary identity signal and must always match.\n  if (left.ino !== right.ino) {\n    return false;\n  }\n  // libuv 1.49.0 through 1.50.x resolve path-based stat() and lstat() on Windows\n  // through GetFileInformationByName, which leaves the volume serial unset, while\n  // fstat() on an open handle reports it. Comparing the two then never matches and\n  // every vault read and write is rejected. libuv 82cdfb75f fixed this in 1.51.0,\n  // so only Node 22.12-22.16 and 24.0-24.1 are affected, but the guard should not\n  // depend on the runtime's patch level. Compare dev only when both sides report\n  // one; POSIX always does, so the original strict behaviour is preserved there.\n  if (!left.dev || !right.dev) {\n    return true;","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/memory-vault.js#L101-L137","documentation":"assertMemoryDirectorySafe throws when the memory root itself (or a directory encountered while walking to it) is a symlink, blocking symlink-based escapes from the vault. The faulting input is the symlinked directory path in the message.","triggerScenarios":"Thrown at scripts/lib/memory-vault.js:119 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Remove the symlink and use a real directory for memory storage.","Point ECC_MEMORY_* env vars at the physical path instead of a symlinked one.","If symlinks are intentional in your setup, relocate the vault root above the link."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"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"}