Version: 1.0.6 · OS: macOS
scripts/session-lifecycle-hook.mjs handleSessionEnd loads broker.json for the session cwd and passes its pid to teardownBrokerSession, which calls terminateProcessTree(pid) (scripts/lib/broker-lifecycle.mjs, scripts/lib/process.mjs) with no check that the process is still an app-server-broker.mjs — no argv, start-time, or socket-ownership comparison. broker.json is only removed by a SessionEnd whose cwd matches, so entries whose broker died some other way (worktree removed, session killed, machine slept) stay behind indefinitely, and their pids get recycled.
Observed on 1.0.6, macOS, 16 days of uptime: 320 broker.json files under ~/.claude/plugins/data/codex-openai-codex/state/ (343 state dirs in total); 4 of them name a pid that is alive today and belongs to something else:
224-scope-backlog-skills-to-backlog-column-358be27031764eea/broker.json -> pid 73768 is now: Slack ShipIt
265-add-verification-must-be-able-to-fail-rule-c33891ccc7c234eb/broker.json -> pid 21722 is now: login
360-share-master-board-workflow-2cba6deeb0cafbd8/broker.json -> pid 60269 is now: Wispr Flow Helper
97-simplify-push-guard-refspec-config-782d049f8463288a/broker.json -> pid 2046 is now: WallpaperSonomaExtension
A session that ends in a cwd with one of those entries sends SIGTERM to that process group.
Related, already on file (linked rather than repeated): #380 (cwd-hash lookup misses brokers whose job cwd ≠ session cwd, which is how these entries go stale), #605 / #543 (brokers never self-terminate). #521 reports the same missing validation as an attacker-gated security issue on shared Linux hosts with a world-writable os.tmpdir(); this report is the accidental path to the same primitive — no attacker, no shared host, and it reproduces on macOS, which #521 explicitly excludes.
This report is only the identity check: before signalling broker.json's pid, confirm the process is still a broker — e.g. compare its argv against the recorded endpoint/pid-file, or the pid-file's own contents — and drop the entry instead of killing when it is not.
Repro: pick any stale broker.json whose pid is alive and is not a broker, run a session in that cwd, /quit; the unrelated process receives SIGTERM.
Version: 1.0.6 · OS: macOS
scripts/session-lifecycle-hook.mjshandleSessionEndloadsbroker.jsonfor the session cwd and passes itspidtoteardownBrokerSession, which callsterminateProcessTree(pid)(scripts/lib/broker-lifecycle.mjs,scripts/lib/process.mjs) with no check that the process is still anapp-server-broker.mjs— no argv, start-time, or socket-ownership comparison.broker.jsonis only removed by a SessionEnd whose cwd matches, so entries whose broker died some other way (worktree removed, session killed, machine slept) stay behind indefinitely, and their pids get recycled.Observed on 1.0.6, macOS, 16 days of uptime: 320
broker.jsonfiles under~/.claude/plugins/data/codex-openai-codex/state/(343 state dirs in total); 4 of them name a pid that is alive today and belongs to something else:A session that ends in a cwd with one of those entries sends SIGTERM to that process group.
Related, already on file (linked rather than repeated): #380 (cwd-hash lookup misses brokers whose job cwd ≠ session cwd, which is how these entries go stale), #605 / #543 (brokers never self-terminate). #521 reports the same missing validation as an attacker-gated security issue on shared Linux hosts with a world-writable
os.tmpdir(); this report is the accidental path to the same primitive — no attacker, no shared host, and it reproduces on macOS, which #521 explicitly excludes.This report is only the identity check: before signalling
broker.json's pid, confirm the process is still a broker — e.g. compare its argv against the recorded endpoint/pid-file, or the pid-file's own contents — and drop the entry instead of killing when it is not.Repro: pick any stale
broker.jsonwhose pid is alive and is not a broker, run a session in that cwd,/quit; the unrelated process receives SIGTERM.