fix: four bug fixes — bold plan checkboxes, BACKLOG recommendations, executor_model regression tests, session_id path traversal

- fix(#1572): phase complete now marks bold-wrapped plan checkboxes in ROADMAP.md
  (`- [ ] **01-01**` format) by allowing optional `**` around plan IDs in the
  planCheckboxPattern regex in both phase.cjs and roadmap.cjs

- fix(#1569): manager init no longer recommends 999.x (BACKLOG) phases as next
  actions; add guard in cmdManagerInit that skips phases matching /^999(?:\.|$)/

- fix(#1568): add regression tests confirming init execute-phase respects
  model_overrides for executor_model, including when resolve_model_ids is 'omit'

- fix(#1533): reject session_id values containing path traversal sequences
  (../,  /, \) in gsd-context-monitor and gsd-statusline before constructing
  /tmp file paths; add security tests covering both hooks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-04-03 11:19:42 -04:00
parent 8903202d62
commit 00e0446b99
9 changed files with 207 additions and 5 deletions

View File

@@ -45,6 +45,13 @@ process.stdin.on('end', () => {
process.exit(0);
}
// Reject session IDs that contain path traversal sequences or path separators.
// session_id is used to construct file paths in /tmp — an unsanitized value
// could escape the temp directory and read or write arbitrary files.
if (/[/\\]|\.\./.test(sessionId)) {
process.exit(0);
}
// Check if context warnings are disabled via config
const cwd = data.cwd || process.cwd();
const configPath = path.join(cwd, '.planning', 'config.json');

View File

@@ -35,7 +35,10 @@ process.stdin.on('end', () => {
// Write context metrics to bridge file for the context-monitor PostToolUse hook.
// The monitor reads this file to inject agent-facing warnings when context is low.
if (session) {
// Reject session IDs with path separators or traversal sequences to prevent
// a malicious session_id from writing files outside the temp directory.
const sessionSafe = session && !/[/\\]|\.\./.test(session);
if (sessionSafe) {
try {
const bridgePath = path.join(os.tmpdir(), `claude-ctx-${session}.json`);
const bridgeData = JSON.stringify({