thedotmack/claude-mem · error

Refusing CCS Align write outside the seat-owned ccs-align…

Error message

Refusing CCS Align write outside the seat-owned ccs-align root

What it means

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.

Solutions

  1. Build the target path with path.join(ccsAlignViewerDir(dataRoot, viewerId), relativeName) so it is anchored inside the seat root.
  2. Check the resolved path: ensure path.resolve(filePath).startsWith(path.resolve(ccsAlignViewerDir(dataRoot, viewerId)) + path.sep).
  3. Fix any traversal segments (../) or wrong viewerId in the path before calling landObservationsInMiddleCache.

Example fix

// before: unanchored path can escape the seat root
const p = path.join(dataRoot, 'ccs-align', relativePath);

// after: anchor inside the seat-owned viewer dir
const p = path.join(ccsAlignViewerDir(dataRoot, viewerId), relativePath);
Defensive patterns

Strategy: validation

Validate before calling

import path from 'path';
function isInsideSeatRoot(dataRoot: string, viewerId: string, filePath: string): boolean {
  const expectedRoot = path.resolve(ccsAlignViewerDir(dataRoot, viewerId));
  const resolved = path.resolve(filePath);
  return resolved === expectedRoot || resolved.startsWith(expectedRoot + path.sep);
}

Try / catch

try {
  landObservationsInMiddleCache(dataRoot, viewerId, filePath, observations);
} catch (err) {
  if (err instanceof Error && err.message.includes('outside the seat-owned ccs-align root')) {
    // rebuild path via ccsAlignViewerDir(dataRoot, viewerId) and retry once
  } else throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17). Data as JSON: /api/errors/6531fc2ed088103f. Report an issue: GitHub.

Appendix: source

Thrown at src/services/integrations/CcsAlignMiddleCache.ts:283

    excludedObsIds.add(mark.observationId);
    for (const tid of mark.toolUseIds) {
      excludedToolUseIds.add(tid);
    }
  }
  return { excludedObsIds, excludedToolUseIds };
}

/**
 * Refuse any write that escapes the seat-owned CCS Align root, targets
 * `profile.md`, or lands inside an `agents/.../memory/log` tree (that is the
 * #3931 pusher's seam, never Align's). Shape copied from
 * `assertSafeAwarenessLogPath` (#3931).
 */
export function assertSafeMiddleCachePath(dataRoot: string, viewerId: string, filePath: string): void {
  const expectedRoot = path.resolve(ccsAlignViewerDir(dataRoot, viewerId));
  const resolved = path.resolve(filePath);
  if (!resolved.startsWith(expectedRoot + path.sep) && resolved !== expectedRoot) {
    throw new Error('Refusing CCS Align write outside the seat-owned ccs-align root');
  }
  if (path.basename(resolved) === 'profile.md') {
    throw new Error('Refusing CCS Align write to profile.md');
  }
  if (/(^|[\\/])agents[\\/].*[\\/]memory[\\/]log([\\/]|$)/.test(resolved)) {
    throw new Error('Refusing CCS Align write into agents/**/memory/log (that seam belongs to #3931)');
  }
}

export function buildCcsAlignRecord(obs: CcsAlignObservationInput, now: Date = new Date()): CcsAlignMiddleRecord {
  return {
    v: RECORD_VERSION,
    id: obs.id,
    type: obs.type,
    title: obs.title ?? null,
    created_at: obs.created_at ?? null,
    project: obs.project ?? null,
    agent_id: obs.agent_id ?? null,

View on GitHub (pinned to d8bc9755e7)