[RSI, security] fix(kernel): keep the kernel stderr log owner-only - #2425
sethkarten wants to merge 2 commits into
Conversation
The kernel stderr log (session-artifacts/<id>/kernel-stderr.log) was created world-readable (0644) while every sibling artifact in the same private directory is owner-only (0600 files, 0700 dirs). Kernel stderr can carry exception payloads and library warnings, so the log and its directory must match the other private session artifacts. Create both with owner-only bits: mode 0o700 for the directory and 0o600 for the file, with fchmodSync on the opened descriptor to enforce the exact bits despite the umask (and tighten a pre-existing loose log on next kernel start).
Prime Agent performance — completedPR Overall: 0 regressed · 1 improved · 39 no clear change.
Python runtime
UI interactions
Sandbox cost: ~$0.1419 — no inference calls. Methodology and samplesMain resolved at 2026-09-16T23:46:40.168225+00:00. Harness
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit c023913. Configure here.
Rotating an oversized kernel stderr log renamed it to `.old` before any chmod, so a pre-existing world-readable (0644) log kept those bits and its historical exception payloads stayed readable by other users. Only the new current file was tightened. chmod the log to KERNEL_STDERR_LOG_MODE immediately before the rename. The path is known to exist (statSync just succeeded), a chmod failure lands in the existing rotation catch and keeps appending instead, and on Windows the chmod clears the read-only bit so the rename still proceeds. Cover it with a regression test that pre-creates an oversized 0644 log and asserts the rotated file is 0600. The failing-start tests now share fakeRuntime/withManager helpers to keep the added coverage line-neutral.

What
The kernel stderr log (
kernel-stderr.login the session artifact directory) was created world-readable (openSync(path, "a")default mode -> 0644) while every sibling artifact in the same private directory is owner-only:kernel-state.dill/kernel-state.json0600,semantic-edges.jsonl0600,rlm-subagent.json0600, and the daemon journals use 0700 dirs + 0600 files. Kernel stderr can carry Python exception payloads and library warnings, so it belongs to the private set.This creates the log owner-only (0600) and its directory owner-only (0700) when the kernel manager itself creates it, with
fchmodSyncon the opened descriptor so the exact bits hold despite the umask (and a pre-existing loose log is tightened on the next kernel start).Why this shape
mkdirSync(dirname(path), { recursive: true, mode: 0o700 })mirrorscommand-recovery-journal.ts,worker-recovery-journal.ts, andrlm-ledger.ts.openSync(path, "a", 0o600)+fchmodSyncmirrorsauth-storage.ts's fchmod idiom; the stderr log is a persistent append fd with a byte budget, so thewriteFileAtomicSynctemp+rename pattern does not apply. The fd is closed if the fchmod fails (no leak window).renameSyncto.old) preserves the mode, so rotated logs stay owner-only.Tests
Extends the existing teardown test in
test/repl-kernel-startup.test.ts(fake runtime that exits before ready, log path in a nested dir the manager creates) with two assertions: file mode 0600 and directory mode 0700. Both fail pre-fix (0644/0755) and pass post-fix; proven pre-fix by stashing the source change and rerunning (received 0o644 vs expected 0o600).Validation
npm run checkclean at the tip: biome,check:test-policy(vs origin/main),tsgo --noEmit,check:installer,check:browser-smoke.npx vitest --run test/repl-kernel-startup.test.ts: 5/5.Dedup
Complementary, not overlapping: #1249 (private-files.ts utility; covers session-manager/config/state-snapshot/agent-session storage; does not touch this log) and #2174 (kernel-env allowlist hunks in the same file, disjoint from
openStderrLog; its docs explicitly keep the stderr log as-is). Nobash.pyguard-class overlap with #2373/#2384/#2390/#2395/#2413/#2415.Note
Low Risk
Narrow filesystem permission change with tests; opening may fail if the process cannot chmod a log owned by another user.
Overview
Hardens permissions on
kernel-stderr.logso it matches other private session artifacts (kernel state, semantic edges, etc.), since stderr can include Python exception payloads.ReplKernelManager.openStderrLognow creates the log directory at 0700 and opens the log at 0600, withfchmodSyncon the descriptor so mode holds under umask and existing loose files are tightened on the next open. Before rotation to.old,chmodSyncruns so historical rotated logs are not left world-readable.Startup tests gain shared
fakeRuntime/withManagerhelpers plus assertions on file and directory modes, including a case that seeds an oversized 0644 log and expects rotation to produce 0600 on both the new file and.old.Reviewed by Cursor Bugbot for commit fee75f1. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Fix kernel stderr log permissions to be owner-only in
ReplKernelManagerSets the kernel stderr log directory to mode
0700when newly created and keeps current and rotated log files at mode0600in repl-manager.ts. Before rotating an oversized existing log, the current file is tightened to0600so the renamed.oldfile retains restricted permissions. Iffchmodfails on a log descriptor, the descriptor is closed and the operation fails.0700and log files are0600, including a case that tightens a pre-existing world-readable oversized log before rotation.0600on open and before rotation; callers relying on group/world readability of these files will lose access.Macroscope summarized fee75f1.