SIGN IN SIGN UP

fix(security): don't expand sensitive path defaults unless XDG/CASS_MEMORY_HOME set

Root cause: loadConfig() unconditionally replaced the literal
"~/.cass-memory/playbook.yaml" (and diaryDir) default with an absolute
path produced by resolveGlobalDir() — which reads $HOME. This broke two
security assertions:

  - test/cli-config-cascade.e2e.test.ts
    "repo config cannot override sensitive paths (security)"
  - test/config-security.test.ts
    "prevents repo config from overriding playbookPath and diaryDir"

Both tests verify that when a malicious repo config tries to redirect
playbookPath/diaryDir at a dangerous location (/etc/passwd, /tmp/evil,
etc.), loadConfig() falls back to the safe default. The expected value
is the portable literal "~/.cass-memory/playbook.yaml" (matching
DEFAULT_CONFIG.playbookPath), but the expansion returned a $HOME-rooted
absolute path, failing the toBe() comparison.

Fix: Only resolve the legacy literal to an absolute path when the user
has explicitly opted into a non-default global dir via CASS_MEMORY_HOME
or XDG_DATA_HOME. In the common case we leave the "~/..." literal
alone; downstream callers already run the value through expandPath()
at use-time (playbook.ts, outcome.ts, orchestrator.ts, doctor.ts,
undo.ts, forget.ts, mark.ts, commands/playbook.ts), so behaviour is
preserved for real invocations.

Also preserves the security guarantee: repo configs still cannot
override cassPath / playbookPath / diaryDir / apiKey / baseUrl /
ollamaBaseUrl / cliCommand / budget / sanitization (that stripping
happens earlier in loadConfig() and is unchanged).

Co-Authored-By: Claude <noreply@anthropic.com>
D
Dicklesworthstone committed
2bc1e8bad438328a71c4e983065bcd31fc8aedde
Parent: aaf0107