{"record":{"id":"6531fc2ed088103f","repo":"thedotmack/claude-mem","slug":"refusing-ccs-align-write-outside-the-seat-owned-ccs-align","errorCode":null,"errorMessage":"Refusing CCS Align write outside the seat-owned ccs-align root","messagePattern":"Refusing CCS Align write outside the seat-owned ccs-align root","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/services/integrations/CcsAlignMiddleCache.ts","lineNumber":283,"sourceCode":"    excludedObsIds.add(mark.observationId);\n    for (const tid of mark.toolUseIds) {\n      excludedToolUseIds.add(tid);\n    }\n  }\n  return { excludedObsIds, excludedToolUseIds };\n}\n\n/**\n * Refuse any write that escapes the seat-owned CCS Align root, targets\n * `profile.md`, or lands inside an `agents/.../memory/log` tree (that is the\n * #3931 pusher's seam, never Align's). Shape copied from\n * `assertSafeAwarenessLogPath` (#3931).\n */\nexport function assertSafeMiddleCachePath(dataRoot: string, viewerId: string, filePath: string): void {\n  const expectedRoot = path.resolve(ccsAlignViewerDir(dataRoot, viewerId));\n  const resolved = path.resolve(filePath);\n  if (!resolved.startsWith(expectedRoot + path.sep) && resolved !== expectedRoot) {\n    throw new Error('Refusing CCS Align write outside the seat-owned ccs-align root');\n  }\n  if (path.basename(resolved) === 'profile.md') {\n    throw new Error('Refusing CCS Align write to profile.md');\n  }\n  if (/(^|[\\\\/])agents[\\\\/].*[\\\\/]memory[\\\\/]log([\\\\/]|$)/.test(resolved)) {\n    throw new Error('Refusing CCS Align write into agents/**/memory/log (that seam belongs to #3931)');\n  }\n}\n\nexport function buildCcsAlignRecord(obs: CcsAlignObservationInput, now: Date = new Date()): CcsAlignMiddleRecord {\n  return {\n    v: RECORD_VERSION,\n    id: obs.id,\n    type: obs.type,\n    title: obs.title ?? null,\n    created_at: obs.created_at ?? null,\n    project: obs.project ?? null,\n    agent_id: obs.agent_id ?? null,","sourceCodeStart":265,"sourceCodeEnd":301,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/services/integrations/CcsAlignMiddleCache.ts#L265-L301","documentation":"assertSafeMiddleCachePath() is a path-containment guard for CCS Align middle-cache writes. It resolves the seat-owned root (ccsAlignViewerDir(dataRoot, viewerId)) and throws if the target file resolves outside that directory. The library refuses writes that could escape the per-seat ccs-align root, since landObservationsInMiddleCache must never touch files owned by other seats or system paths.","triggerScenarios":"landObservationsInMiddleCache() calls assertSafeMiddleCachePath(dataRoot, viewerId, filePath) with a filePath that, after path.resolve(), does not start with the seat's ccs-align viewer dir (or equal it) — e.g. a path with ../ traversal, an absolute path into another directory, or a viewerId/filePath mismatch.","commonSituations":"Caller builds the cache path from untrusted or concatenated user input; viewerId changed between computing the path and writing; symlinks or relative paths cause resolution outside the root; a refactor moved files out of ccs-align/<viewerId>/ but the write path was not updated.","solutions":["Build the target path with path.join(ccsAlignViewerDir(dataRoot, viewerId), relativeName) so it is anchored inside the seat root.","Check the resolved path: ensure path.resolve(filePath).startsWith(path.resolve(ccsAlignViewerDir(dataRoot, viewerId)) + path.sep).","Fix any traversal segments (../) or wrong viewerId in the path before calling landObservationsInMiddleCache."],"exampleFix":"// before: unanchored path can escape the seat root\nconst p = path.join(dataRoot, 'ccs-align', relativePath);\n\n// after: anchor inside the seat-owned viewer dir\nconst p = path.join(ccsAlignViewerDir(dataRoot, viewerId), relativePath);","handlingStrategy":"validation","validationCode":"import path from 'path';\nfunction isInsideSeatRoot(dataRoot: string, viewerId: string, filePath: string): boolean {\n  const expectedRoot = path.resolve(ccsAlignViewerDir(dataRoot, viewerId));\n  const resolved = path.resolve(filePath);\n  return resolved === expectedRoot || resolved.startsWith(expectedRoot + path.sep);\n}","typeGuard":null,"tryCatchPattern":"try {\n  landObservationsInMiddleCache(dataRoot, viewerId, filePath, observations);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('outside the seat-owned ccs-align root')) {\n    // rebuild path via ccsAlignViewerDir(dataRoot, viewerId) and retry once\n  } else throw err;\n}","preventionTips":["Always derive cache paths from ccsAlignViewerDir(dataRoot, viewerId) instead of string concatenation.","Sanitize user-supplied relative segments (reject '..').","Keep viewerId consistent between path construction and write calls."],"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"}