{"record":{"id":"2672549ca833a216","repo":"thedotmack/claude-mem","slug":"refusing-write-to-profile-md","errorCode":null,"errorMessage":"Refusing write to profile.md","messagePattern":"Refusing write to profile\\.md","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/services/integrations/grok-bot-index-format.ts","lineNumber":172,"sourceCode":"    .join('\\n');\n}\n\nexport 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) {","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/services/integrations/grok-bot-index-format.ts#L154-L190","documentation":"assertSafeInjectPath validates a destination path before the memory writer writes to it. profile.md is a user-owned agent file that this writer must never modify, so any write target named profile.md (case-insensitive) is rejected outright.","triggerScenarios":"refreshSeatIndex or ensureIndexLogDir computes a write path whose basename is profile.md — e.g. a caller passes the profile file instead of the inject-log basename into the write path guard.","commonSituations":"A caller confuses the inject log with the agent profile file; refactored code reuses the writer for profile updates; a dynamic filename ends up as 'Profile.md'.","solutions":["Write to INJECT_LOG_BASENAME (the owned log file) inside agents/<agentId>/memory/log instead of profile.md.","Update the calling code so profile content is handled by the profile-specific writer, not the inject-log writer.","Check the resolved basename before calling and skip the write when it is profile.md."],"exampleFix":"// before\nwriteInject(root, agentId, path.join(dir, 'profile.md'), data);\n// after\nwriteInject(root, agentId, injectLogPath(root, agentId), data);","handlingStrategy":"validation","validationCode":"if (path.basename(path.resolve(target)).toLowerCase() === 'profile.md') {\n  throw new Error('use the profile writer, not the inject writer');\n}","typeGuard":null,"tryCatchPattern":"try {\n  assertSafeInjectPath(root, agentId, target);\n  writeFileAtomic(target, data);\n} catch (err) {\n  logger.error('Inject write rejected', { target }, err);\n}","preventionTips":["Derive write targets only from injectLogPath().","Keep profile.md managed by its dedicated writer.","Never pass caller-supplied filenames into the inject writer."],"tags":["path","safety","write"],"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"}