From 1cc1930ad9b6b665b1ba2dfdb03b6af40ee2e22d Mon Sep 17 00:00:00 2001 From: John Morrissey <544926+tachyon-beep@users.noreply.github.com> Date: Tue, 1 Sep 2026 02:19:14 +1000 Subject: [PATCH] fix(cli): keep session hook environment clean --- crates/loomweave-cli/src/main.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/crates/loomweave-cli/src/main.rs b/crates/loomweave-cli/src/main.rs index 0e7f011b..96a23ee9 100644 --- a/crates/loomweave-cli/src/main.rs +++ b/crates/loomweave-cli/src/main.rs @@ -177,13 +177,16 @@ fn main() -> Result<()> { /// /// Most operator commands want `.env` loaded (e.g. a `.env`-supplied `RUST_LOG`, /// or a Filigree `token_env` consumed by `guidance promote` / `sarif import`). -/// Two cases must NOT load it, because they would import repository-controlled +/// Three cases must NOT load it, because they would import repository-controlled /// values into a subprocess environment before those values have been vetted: /// /// - `analyze` (and `worktree analyze`, which runs the identical pipeline): /// project `.env` contents are scanned as source sidecars by the /// pre-ingest secret scanner and must not reach plugin subprocess /// environments before that gate runs. +/// - `hook`: a stale index starts a detached `analyze`, so loading `.env` in the +/// hook would bypass the direct `analyze` exclusion by passing those values to +/// the child in its inherited environment. /// - `guidance create` / `guidance edit`: authoring spawns `$VISUAL`/`$EDITOR` /// (see `guidance::edit_in_editor`), so a repository `.env` supplying /// `VISUAL`/`EDITOR` — or `PATH`, etc. — would execute attacker-controlled @@ -198,6 +201,7 @@ fn should_load_dotenv(command: &cli::Command) -> bool { | cli::Command::Worktree { command: cli::WorktreeCommand::Analyze { .. }, } + | cli::Command::Hook { .. } | cli::Command::Guidance { command: cli::GuidanceCommand::Create { .. } | cli::GuidanceCommand::Edit { .. }, } @@ -241,6 +245,19 @@ mod tests { ])); } + #[test] + fn session_start_hook_does_not_load_dotenv() { + // A stale session-start hook spawns analyze; repo values must not be + // inherited by that child before analyze's secret scan runs. + assert!(!loads(&[ + "loomweave", + "hook", + "session-start", + "--path", + ".", + ])); + } + #[test] fn guidance_editor_subcommands_do_not_load_dotenv() { // create/edit spawn $VISUAL/$EDITOR; a repo .env must not feed them.