{"record":{"id":"b6464899d657503d","repo":"thedotmack/claude-mem","slug":"refusing-inject-write-outside-agent-memory-log","errorCode":null,"errorMessage":"Refusing inject write outside agent memory/log","messagePattern":"Refusing inject write outside agent memory/log","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/services/integrations/grok-bot-index-format.ts","lineNumber":175,"sourceCode":"export function shouldRewriteInject(existingContents: string, nextContents: string): boolean {\n  return factBlock(existingContents) !== factBlock(nextContents);\n}\n\nexport function injectLogPath(agentDataRoot: string, agentId: string): string {\n  if (!AGENT_ID_RE.test(agentId)) {\n    throw new Error(`Refusing inject path for non-UUID agent id: ${agentId}`);\n  }\n  return path.join(agentDataRoot, 'agents', agentId, 'memory', 'log', INJECT_LOG_BASENAME);\n}\n\nexport function assertSafeInjectPath(agentDataRoot: string, agentId: string, filePath: string): void {\n  const expectedDir = path.resolve(path.join(agentDataRoot, 'agents', agentId, 'memory', 'log'));\n  const resolved = path.resolve(filePath);\n  if (path.basename(resolved).toLowerCase() === 'profile.md') {\n    throw new Error('Refusing write to profile.md');\n  }\n  if (path.dirname(resolved) !== expectedDir) {\n    throw new Error('Refusing inject write outside agent memory/log');\n  }\n  if (path.basename(resolved) !== INJECT_LOG_BASENAME) {\n    throw new Error(`Refusing inject write to a file this writer does not own: ${path.basename(resolved)}`);\n  }\n}\n\nfunction writeFileAtomic(filePath: string, contents: string): void {\n  mkdirSync(path.dirname(filePath), { recursive: true });\n  const tmp = `${filePath}.tmp-${process.pid}-${Date.now()}`;\n  writeFileSync(tmp, contents, 'utf8');\n  renameSync(tmp, filePath);\n}\n\nexport function writeFileIfChanged(filePath: string, contents: string): { changed: boolean; filePath: string } {\n  if (existsSync(filePath) && readFileSync(filePath, 'utf8') === contents) {\n    return { changed: false, filePath };\n  }\n  writeFileAtomic(filePath, contents);","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/services/integrations/grok-bot-index-format.ts#L157-L193","documentation":"assertSafeInjectPath confines all writes to the directory agentDataRoot/agents/<agentId>/memory/log. If the resolved path's parent directory differs from that expected directory, it throws, blocking writes anywhere else on the filesystem (traversal/symlink protection).","triggerScenarios":"refreshSeatIndex or ensureIndexLogDir passes a filePath whose path.resolve'd dirname is not exactly the agent's memory/log directory — e.g. paths containing '..', absolute paths to other folders, or symlinked locations that resolve elsewhere.","commonSituations":"Caller joins a user-supplied subpath; agent data root was moved or symlinked so realpath diverges; a typo passes 'logs' instead of 'log'.","solutions":["Always build the target path with injectLogPath(agentDataRoot, agentId) so it lands inside memory/log.","Remove any '..' segments or user-supplied path components from the target before calling.","Verify agentDataRoot matches the actual (realpath'd) root so expectedDir equals the resolved dirname."],"exampleFix":"// before\nconst p = path.join(root, 'agents', agentId, 'memory', 'logs', 'inject.md');\n// after\nconst p = injectLogPath(root, agentId); // .../memory/log/<INJECT_LOG_BASENAME>","handlingStrategy":"validation","validationCode":"const expected = path.resolve(path.join(root, 'agents', agentId, 'memory', 'log'));\nif (path.dirname(path.resolve(target)) !== expected) {\n  throw new Error('target escapes agent memory/log');\n}","typeGuard":null,"tryCatchPattern":"try {\n  assertSafeInjectPath(root, agentId, target);\n} catch (err) {\n  logger.error('Refusing unsafe inject path', { target }, err);\n  return;\n}","preventionTips":["Never interpolate user input into the target path.","Use injectLogPath() as the single source of valid targets.","Be aware of symlinks: resolve real paths before validating."],"tags":["path","security","traversal"],"backgroundTag":"path-traversal-blocked","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}