Skip to content

fix(home): fail loud instead of falling back to os.tmpdir in getUserHome - #310

Merged
jeff-r2026 merged 1 commit into
mainfrom
fix/home-fail-loud
Aug 24, 2026
Merged

fix(home): fail loud instead of falling back to os.tmpdir in getUserHome#310
jeff-r2026 merged 1 commit into
mainfrom
fix/home-fail-loud

Conversation

@jeff-r2026

Copy link
Copy Markdown
Collaborator

Follow-up to #309

#309 ended getUserHome()'s fallback chain with || os.tmpdir() to guarantee a non-empty path. A post-merge security review flagged this as exploitable:

  • [HIGH] code executionbuiltin-hooks.ts (resolveCodebuddyNode / resolveWorkbuddyNode) scans getUserHome() for a node binary and executes it. If the fallback returns os.tmpdir() (world-writable), an attacker who can drop /tmp/.codebuddy-server/.../node gets their binary run.
  • [MEDIUM] credential exposureapi-key.ts writes the API key under getUserHome()/.teamai/apikey; a /tmp fallback would place credentials in a shared directory.

Fix

getUserHome() now throws when none of HOME, USERPROFILE, or os.homedir() resolves, instead of falling back to os.tmpdir(). The empty-string case the tmpdir() fallback was guarding against (cwd-relative paths) is likewise covered by throwing. On any real machine at least one of the three is set, so this branch is only reached in pathological contexts (passwd-less uid, env -i) where refusing to run is the safe behavior.

Test Plan

  • npx tsc --noEmit — clean
  • npx vitest run — 2142 passed
  • npm run build — success
  • Regression test updated to assert getUserHome() throws when os.homedir() is mocked to ''

🤖 Generated with Claude Code

Follow-up to #309. That PR ended getUserHome()'s fallback chain with
`|| os.tmpdir()` to guarantee a non-empty path. But callers join the result
onto `.teamai/...` to write credentials (api-key.ts) and to resolve and execute
a node binary (builtin-hooks.ts resolveCodebuddyNode/resolveWorkbuddyNode), so
falling back to a world-writable shared directory is a code-execution and
credential-exposure vector: an attacker who can write /tmp/.codebuddy-server/.../node
would get their binary run.

Throw when none of HOME, USERPROFILE, or os.homedir() resolves instead. The
empty-string case os.tmpdir() was guarding against (cwd-relative paths) is also
covered by throwing. On any real machine at least one of the three is set, so
this path is only reached in pathological contexts (passwd-less uid, `env -i`)
where refusing to run is the correct, safe behavior.

Update the regression test to assert the throw.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jeff-r2026
jeff-r2026 merged commit 953b0ba into main Aug 24, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant