Skip to content

fix(tui): write the command history owner-only#55

Open
clawedassistant26 wants to merge 1 commit into
moshcoder:mainfrom
clawedassistant26:fix/history-file-world-readable
Open

fix(tui): write the command history owner-only#55
clawedassistant26 wants to merge 1 commit into
moshcoder:mainfrom
clawedassistant26:fix/history-file-world-readable

Conversation

@clawedassistant26

Copy link
Copy Markdown
Contributor

The bug

The pit saves every line typed at the mosh prompt to ~/.moshcode_history, and saveHistory() passed no mode, so the file is created 0644 under a normal umask. Any other account on the machine can read it.

That matters because the documented TUI flows put secrets on the command line:

  • /mcp install <url> -H "Authorization: Bearer <token>"
  • /secrets … (logicsrc credentials), /coinpay …, /ugig …
  • the ! shell escape, e.g. !export STRIPE_KEY=sk_live_…

src/auth.mjs already writes credentials.json with mode: 0o600, so the standard for secret-bearing files in this repo is owner-only. The history file just missed it.

Repro (executed on unmodified main, real TTY)

$ T=$(mktemp -d)
$ printf '/pwd\n/mcp install https://mcp.example.com/sse -H "Authorization: Bearer sk-live-SUPERSECRET"\n/quit\n' \
    | HOME=$T script -qec "node bin/moshcode.mjs" /dev/null
$ stat -c %a $T/.moshcode_history
644
$ cat $T/.moshcode_history
/quit
/mcp install https://mcp.example.com/sse -H "Authorization: Bearer sk-live-SUPERSECRET"
/pwd

The fix

src/tui.mjs only:

  • saveHistory() writes with { mode: 0o600 }.
  • It then chmodSync(…, 0o600). This is the part that matters for existing users: Node applies mode only when the file is created, so every history file already on disk would otherwise keep its 0644 bits forever. Tightening on each save fixes those in place.
  • Still fully best-effort inside the existing try/catch — history is a convenience and must never be fatal. On Windows chmod is a no-op for these bits and does not throw.

Tests

Two added to test/tui.test.mjs, both driving the real CLI in a child process with HOME pointed at a temp dir:

  1. a fresh history file is 0600;
  2. a pre-existing 0644 history file is tightened to 0600 and its contents survive.

Both skip on win32 (POSIX permission bits).

Stash-verified with git stash push -- src/: both FAIL unpatched (9 pass / 2 fail), 11/11 with the fix.
Full suite node --test: 166 tests / 163 pass / 0 fail / 3 skipped (main baseline measured this run: 164 / 161 / 0 fail / 3 skipped).

The pit persists every line typed at the mosh prompt to ~/.moshcode_history,
and the documented flows put secrets on those lines: `/mcp install <url> -H
"Authorization: Bearer …"`, `/secrets`, `/coinpay`, and the `!` shell escape.
saveHistory() passed no mode, so the file was created 0644 under a normal
umask and every other account on the machine could read it.

Write it 0600 and chmod it on every save, since `mode` is ignored when the
file already exists — that is what fixes the history files existing installs
have already written. Matches what auth.mjs already does for credentials.json.
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