{"record":{"id":"9ea275a7a90f3867","repo":"thedotmack/claude-mem","slug":"refusing-awareness-write-outside-agent-memory-log","errorCode":null,"errorMessage":"Refusing awareness write outside agent memory/log","messagePattern":"Refusing awareness write outside agent memory/log","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/services/integrations/GrokBotAwarenessPusher.ts","lineNumber":101,"sourceCode":"  if (line.length <= MAX_LINE_CHARS) return line;\n  return `${line.slice(0, MAX_LINE_CHARS - 1)}…`;\n}\n\nexport function awarenessLineBody(line: string): string {\n  const idx = line.indexOf(AWARENESS_TAG);\n  return idx >= 0 ? line.slice(idx).trim() : line.trim();\n}\n\nexport function grokBotAwarenessLogPath(agentDataRoot: string, agentId: string, now: Date = new Date()): string {\n  const yearMonth = now.toISOString().slice(0, 7);\n  return path.join(agentDataRoot, 'agents', agentId, 'memory', 'log', `${yearMonth}.md`);\n}\n\nfunction assertSafeAwarenessLogPath(agentDataRoot: string, agentId: string, logPath: string): void {\n  const expectedRoot = path.resolve(path.join(agentDataRoot, 'agents', agentId, 'memory', 'log'));\n  const resolved = path.resolve(logPath);\n  if (!resolved.startsWith(expectedRoot + path.sep) && resolved !== expectedRoot) {\n    throw new Error('Refusing awareness write outside agent memory/log');\n  }\n  if (path.basename(resolved) === 'profile.md') {\n    throw new Error('Refusing awareness write to profile.md');\n  }\n}\n\nexport function appendAwarenessLineAtomic(logPath: string, line: string): boolean {\n  const dir = path.dirname(logPath);\n  mkdirSync(dir, { recursive: true });\n\n  const existing = existsSync(logPath) ? readFileSync(logPath, 'utf8') : '';\n  const incomingBody = awarenessLineBody(line);\n  const alreadyPresent = existing\n    .split('\\n')\n    .some(existingLine => existingLine.trim() && awarenessLineBody(existingLine) === incomingBody);\n  if (alreadyPresent) {\n    return false;\n  }","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/services/integrations/GrokBotAwarenessPusher.ts#L83-L119","documentation":"assertSafeAwarenessLogPath() validates that awareness writes from the Grok bot pusher stay inside the agent's own memory/log directory (agentDataRoot/agents/<agentId>/memory/log). It resolves both paths and throws if the target escapes that root, preventing awareness appends from touching arbitrary filesystem locations.","triggerScenarios":"notifyGrokBotAwareness() calls assertSafeAwarenessLogPath(agentDataRoot, agentId, logPath) with a logPath that resolves outside the per-agent memory/log dir — e.g. path built with ../ segments, an absolute path elsewhere, or an agentId that does not match the one baked into the log path.","commonSituations":"Caller constructs the log path from concatenated IDs or user-supplied agent names; agentId renamed/migrated so the stored log path no longer matches; relative vs absolute path mixing; symlinks resolving outside the root.","solutions":["Build the log path as path.join(agentDataRoot, 'agents', agentId, 'memory', 'log', filename) so it is anchored in the expected root.","Verify the agentId used to compute the path matches the agentId passed to notifyGrokBotAwareness.","Strip or reject any ../ traversal segments from the logPath before calling."],"exampleFix":"// before: path not anchored to the agent's memory/log\nconst logPath = path.join(agentDataRoot, 'agents', rel);\n\n// after\nconst logPath = path.join(agentDataRoot, 'agents', agentId, 'memory', 'log', 'awareness.md');","handlingStrategy":"validation","validationCode":"import path from 'path';\nfunction isInsideAgentLogRoot(agentDataRoot: string, agentId: string, logPath: string): boolean {\n  const expectedRoot = path.resolve(path.join(agentDataRoot, 'agents', agentId, 'memory', 'log'));\n  const resolved = path.resolve(logPath);\n  return resolved === expectedRoot || resolved.startsWith(expectedRoot + path.sep);\n}","typeGuard":null,"tryCatchPattern":"try {\n  notifyGrokBotAwareness(agentDataRoot, agentId, logPath, line);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('outside agent memory/log')) {\n    // rebuild logPath from agentDataRoot/agents/<agentId>/memory/log and retry\n  } else throw err;\n}","preventionTips":["Construct awareness log paths with path.join(agentDataRoot, 'agents', agentId, 'memory', 'log', ...).","Reject '..' segments in any user-influenced path component.","Keep agentId consistent between path building and the pusher call."],"tags":["filesystem","path-traversal","security","validation"],"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"}