Skip to content

fix(core): remove detached spawn flag to prevent SIGHUP in PTY enviro… - #27248

Closed
ProthamD wants to merge 7 commits into
google-gemini:mainfrom
ProthamD:fix/shell-sighup-wsl2-bun-issue-16248
Closed

fix(core): remove detached spawn flag to prevent SIGHUP in PTY enviro…#27248
ProthamD wants to merge 7 commits into
google-gemini:mainfrom
ProthamD:fix/shell-sighup-wsl2-bun-issue-16248

Conversation

@ProthamD

@ProthamD ProthamD commented May 19, 2026

Copy link
Copy Markdown
Contributor

Body

Situation:
Users on WSL2, Kitty, and Alacritty reported all shell commands instantly dying with Command terminated by signal: 1 (SIGHUP). These environments aggressively send SIGHUP to detached process groups that lack a controlling terminal.

Task:
Fix the SIGHUP crash without sacrificing process isolation (security).

Action:
This PR prepends trap '' HUP; to every bash command string on non-Windows platforms, inside prepareExecution. This is the exact mechanism the POSIX nohup utility uses — it sets SIG_IGN for SIGHUP before execution. Unlike a shell-level trap, SIG_IGN is inherited across exec(), meaning every child process spawned by the command also ignores SIGHUP, making the guard genuinely effective.

Critically, detached: !isWindows && !isBun is preserved, keeping full process-group isolation for security:

  • TIOCSTI terminal injection protection remains in place
  • A rogue kill -9 0 inside a child command cannot reach the parent process group

Result:

  • SIGHUP crash fixed across WSL2, Kitty, and Alacritty
  • Zero regression in process isolation or cleanup logic
  • killProcessGroup is unaffected (already handles non-group-leader cleanup via pgrep -P tree walk)
  • 66/66 unit tests passing

Fixes #16248

First-approach

initially tried detached: false, but as you noted, it introduced severe process isolation vulnerabilities (TIOCSTI and kill -9 0 DoS).

Second-approach

We restored detached: true to keep full isolation. To fix the SIGHUP bug, we now prepend trap '' HUP; to the command. Because SIG_IGN is inherited across exec() (just like nohup), this safely prevents PTY environments from killing the process while keeping security boundaries intact.

@ProthamD
ProthamD requested a review from a team as a code owner May 19, 2026 10:57
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a critical issue where shell commands in Gemini CLI were failing immediately with a SIGHUP signal on PTY-based environments like WSL2, Kitty, and Alacritty. By removing the detached: true configuration during process spawning, we prevent the creation of sessions without a controlling terminal, which were being aggressively cleaned up by these environments. The change ensures stability across platforms while maintaining robust process cleanup via existing tree-walking logic.

Highlights

  • Removed detached process flag: Updated the shell execution service to set detached: false universally, preventing the creation of orphaned sessions that trigger SIGHUP in PTY-based environments.
  • Improved process lifecycle management: Verified that existing cleanup mechanisms using killProcessGroup effectively handle process termination without requiring the child to be a process group leader.
  • Test suite updates: Updated unit tests to reflect the removal of the detached flag and renamed relevant test cases to document the fix for WSL2, Kitty, and Alacritty.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@ProthamD

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request modifies the ShellExecutionService to disable process detaching for child processes on Unix-like systems, aiming to resolve SIGHUP issues in PTY-based environments like WSL2, Kitty, and Alacritty. However, the review identifies critical security and reliability regressions resulting from this change, including potential terminal hijacking via TIOCSTI, denial of service risks where a child can kill the parent process group, and broken process cleanup logic that relies on the child being a process group leader. It is recommended to revert this change and explore alternative solutions for handling SIGHUP without sacrificing process isolation.

shell: false,
detached: !isWindows && !isBun,
detached: false,
env: finalEnv,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

The change from detached: true to detached: false for child processes on Unix systems introduces several security and reliability regressions:

  1. Terminal Hijacking (Unix): By sharing the same session as the parent process, child processes retain access to the parent's controlling terminal. This allows a malicious or compromised shell command to use the TIOCSTI ioctl (where enabled) to inject characters into the terminal's input buffer, leading to arbitrary command execution in the user's shell after the CLI tool exits.
  2. Denial of Service (DoS): Child processes are now spawned in the same process group as the parent. A command like kill -9 0 executed by the child will send a SIGKILL to the entire process group, including the parent Gemini CLI process, causing it to crash.
  3. Broken Cleanup Logic: The killProcessGroup utility relies on process.kill(-pid) to terminate process groups. This call fails when detached: false is used because the child is not a process group leader. This makes process cleanup unreliable and, in cases of PID reuse, could lead to sending signals to unrelated process groups.

Remediation:
Revert to using detached: true on Unix systems to maintain process and session isolation. To resolve the SIGHUP issue in PTY-based environments that motivated this change, consider having the child process explicitly ignore SIGHUP or investigating environment-specific configurations that don't require sacrificing isolation.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request disables process detachment in the ShellExecutionService by setting the detached flag to false for spawned child processes. This change addresses issues where processes were receiving SIGHUP and terminating prematurely in PTY-based environments such as WSL2, Kitty, and Alacritty. The update also removes specific logic for Bun and updates the test suite to align with this new behavior. I have no feedback to provide as there were no review comments to evaluate.

@gemini-cli gemini-cli Bot added priority/p1 Important and should be addressed in the near term. priority/p2 Important but can be addressed in a future release. area/core Issues related to User Interface, OS Support, Core Functionality help wanted We will accept PRs from all issues marked as "help wanted". Thanks for your support! labels May 19, 2026
@ProthamD
ProthamD force-pushed the fix/shell-sighup-wsl2-bun-issue-16248 branch from 82dd61a to 317d0dc Compare May 19, 2026 12:08
@ProthamD

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a trap '' HUP command prefix for shell executions on Unix-like systems to ensure child processes ignore hangup signals in PTY environments like WSL2, Kitty, and Alacritty. The changes also include updates to the test suite to reflect this new behavior. Feedback was provided regarding a misleading test description that incorrectly stated a process was not detached when it actually was; a suggestion was made to align the description with the implementation.

Comment thread packages/core/src/services/shellExecutionService.test.ts Outdated
@ProthamD
ProthamD force-pushed the fix/shell-sighup-wsl2-bun-issue-16248 branch from 2036515 to d2c25d1 Compare May 19, 2026 12:41
@ProthamD

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements a fix for SIGHUP signals on Unix-like systems by prepending a trap '' HUP command to shell executions, ensuring child processes ignore hangup signals from PTY environments like WSL2 or Kitty. The changes include updates to ShellExecutionService and its test suite to reflect this new behavior. Feedback suggests explicitly checking for the 'bash' shell type before applying the trap to improve robustness for potential future shell support.

Comment on lines +425 to +428
const hupGuardedCommand = isWindows
? guardedCommand
: `trap '' HUP; ${guardedCommand}`;
const spawnArgs = [...argsPrefix, hupGuardedCommand];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

While this logic is currently correct because 'getShellConfiguration' returns 'bash' for all non-Windows platforms, it implicitly assumes this will always be the case. To improve robustness and prevent potential issues if other shells are supported in the future, it would be safer to explicitly check if 'shell === bash' before prepending the 'trap' command. This would align with the defensive check already present in 'ensurePromptvarsDisabled'.

Suggested change
const hupGuardedCommand = isWindows
? guardedCommand
: `trap '' HUP; ${guardedCommand}`;
const spawnArgs = [...argsPrefix, hupGuardedCommand];
const hupGuardedCommand = !isWindows && shell === 'bash'
? "trap '' HUP; " + guardedCommand
: guardedCommand;
const spawnArgs = [...argsPrefix, hupGuardedCommand];

@ProthamD
ProthamD force-pushed the fix/shell-sighup-wsl2-bun-issue-16248 branch from 484d32c to d9afe11 Compare May 19, 2026 13:05
@ProthamD

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a SIGHUP trap (trap '' HUP) to shell execution commands on Unix systems to prevent premature termination in PTY environments like WSL2, Kitty, and Alacritty. The changes include updating the command preparation logic in ShellExecutionService and adjusting corresponding tests. A security review identified that prepending trap to the command string could potentially bypass existing sandbox command identification logic, which currently does not account for trap as a built-in command. It is recommended to update the filtering logic in shell-utils.ts to include trap to maintain security integrity.

Comment thread packages/core/src/services/shellExecutionService.ts
@ProthamD
ProthamD force-pushed the fix/shell-sighup-wsl2-bun-issue-16248 branch from a24cf86 to 2f6624a Compare May 19, 2026 13:36
@ProthamD

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a trap '' HUP guard for shell commands executed via bash on Unix-like systems, preventing child processes from being terminated by hangup signals in certain PTY environments such as WSL2, Kitty, and Alacritty. Corresponding updates were made to command parsing utilities to ignore the trap builtin and to the test suite to reflect the new command structure. Security feedback identifies a high-severity vulnerability in the getCommandName utility, which is susceptible to privilege escalation via command chaining. The reviewer recommends stricter validation of command roots and suggests centralizing the list of ignored shell builtins to improve maintainability and ensure consistent security filtering.

Comment on lines 32 to 34
const roots = getCommandRoots(stripped).filter(
(r) => r !== 'shopt' && r !== 'set',
(r) => r !== 'shopt' && r !== 'set' && r !== 'trap',
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

The getCommandName utility function is vulnerable to privilege escalation via command chaining. It extracts only the first command root from a potentially chained shell command, allowing an attacker to bypass restrictions by prepending a safe command to a malicious one. Additionally, the list of shell builtins to ignore (shopt, set, trap) is duplicated across shell-utils.ts, MacOsSandboxManager.ts, and commandUtils.ts. Consider extracting this list into a shared constant (e.g., SHELL_BUILTINS_TO_IGNORE) to improve maintainability and ensure consistent security filtering across the codebase.

Suggested change
const roots = getCommandRoots(stripped).filter(
(r) => r !== 'shopt' && r !== 'set',
(r) => r !== 'shopt' && r !== 'set' && r !== 'trap',
);
const roots = getCommandRoots(stripped).filter(
(r) => r !== 'shopt' && r !== 'set' && r !== 'trap',
);
if (roots.length === 1) {
return roots[0];
}
return path.basename(command);

Comment on lines 56 to 58
const roots = getCommandRoots(stripped).filter(
(r) => r !== 'shopt' && r !== 'set',
(r) => r !== 'shopt' && r !== 'set' && r !== 'trap',
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

The getCommandName function is vulnerable to privilege escalation via command chaining. It extracts only the first command root (e.g., git from git; malicious_cmd) and uses it to look up and grant persistent permissions for the entire execution. An attacker can exploit this by prepending a privileged command to a malicious one, causing the sandbox to be configured with the privileges of the first command while executing the entire chain.

This issue is exacerbated by the current PR which prepends trap '' HUP; to commands, as the filtering logic now explicitly skips the prepended trap to find the 'first' command, which might be followed by other malicious commands in a chain.

Suggested change
const roots = getCommandRoots(stripped).filter(
(r) => r !== 'shopt' && r !== 'set',
(r) => r !== 'shopt' && r !== 'set' && r !== 'trap',
);
const roots = getCommandRoots(stripped).filter(
(r) => r !== 'shopt' && r !== 'set' && r !== 'trap',
);
if (roots.length === 1) {
return roots[0];
}
return path.basename(req.command);

@ProthamD
ProthamD force-pushed the fix/shell-sighup-wsl2-bun-issue-16248 branch from cd57ddb to 0720423 Compare May 19, 2026 13:58
@ProthamD

Copy link
Copy Markdown
Contributor Author

/gemini review

@ProthamD
ProthamD force-pushed the fix/shell-sighup-wsl2-bun-issue-16248 branch from 57c5ad4 to 6f80088 Compare May 19, 2026 14:05
@ProthamD
ProthamD requested a review from a team as a code owner May 19, 2026 14:05
@github-actions

Copy link
Copy Markdown

🛑 Action Required: Evaluation Approval

Steering changes have been detected in this PR. To prevent regressions, a maintainer must approve the evaluation run before this PR can be merged.

Maintainers:

  1. Go to the Workflow Run Summary.
  2. Click the yellow 'Review deployments' button.
  3. Select the 'eval-gate' environment and click 'Approve'.

Once approved, the evaluation results will be posted here automatically.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a SHELL_BUILTINS_TO_IGNORE set to standardize command filtering across sandbox managers and adds a trap '' HUP prefix to shell commands on Unix to handle SIGHUP signals in detached sessions. Reviewers have raised significant security concerns regarding the inclusion of trap in the ignore list, noting that it could facilitate sandbox bypasses by allowing malicious commands to be hidden within the trap builtin.

* when identifying the primary command for permission/sandbox checks.
* Centralised here so all callers stay in sync automatically.
*/
export const SHELL_BUILTINS_TO_IGNORE = new Set(['shopt', 'set', 'trap']);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

Including trap in SHELL_BUILTINS_TO_IGNORE introduces a sandbox bypass vulnerability. This allows an attacker to prepend a malicious trap command, which is ignored by the sandbox manager, leading to the execution of malicious code with elevated permissions when the shell exits. It is crucial to carefully evaluate any additions to SHELL_BUILTINS_TO_IGNORE to prevent similar security bypasses.

Suggested change
export const SHELL_BUILTINS_TO_IGNORE = new Set(['shopt', 'set', 'trap']);
export const SHELL_BUILTINS_TO_IGNORE = new Set(['shopt', 'set']);

const stripped = stripShellWrapper(fullCmd);
const roots = getCommandRoots(stripped).filter(
(r) => r !== 'shopt' && r !== 'set',
(r) => !SHELL_BUILTINS_TO_IGNORE.has(r),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

Filtering out trap from the command roots allows an attacker to hide malicious code within a trap builtin. If an attacker provides a command like trap 'rm -rf /' EXIT; git status, this filter will remove trap, leaving only git. The logic then incorrectly identifies the command as a single-root git command and grants it the corresponding sandbox permissions, which the malicious trap can then abuse.

const stripped = stripShellWrapper(fullCmd);
const roots = getCommandRoots(stripped).filter(
(r) => r !== 'shopt' && r !== 'set',
(r) => !SHELL_BUILTINS_TO_IGNORE.has(r),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

Filtering out trap from the command roots allows an attacker to hide malicious code within a trap builtin. If an attacker provides a command like trap 'rm -rf /' EXIT; git status, this filter will remove trap, leaving only git. The logic then incorrectly identifies the command as a single-root git command and grants it the corresponding sandbox permissions, which the malicious trap can then abuse.

const stripped = stripShellWrapper(fullCmd);
const roots = getCommandRoots(stripped).filter(
(r) => r !== 'shopt' && r !== 'set',
(r) => !SHELL_BUILTINS_TO_IGNORE.has(r),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

Filtering out trap from the command roots allows an attacker to hide malicious code within a trap builtin. If an attacker provides a command like trap 'rm -rf /' EXIT; git status, this filter will remove trap, leaving only git. The logic then incorrectly identifies the command as a single-root git command and grants it the corresponding sandbox permissions, which the malicious trap can then abuse.

const stripped = stripShellWrapper(fullCmd);
const roots = getCommandRoots(stripped).filter(
(r) => r !== 'shopt' && r !== 'set',
(r) => !SHELL_BUILTINS_TO_IGNORE.has(r),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

Filtering out trap from the command roots allows an attacker to hide malicious code within a trap builtin. If an attacker provides a command like trap 'rm -rf /' EXIT; git status, this filter will remove trap, leaving only git. The logic then incorrectly identifies the command as a single-root git command and grants it the corresponding sandbox permissions, which the malicious trap can then abuse.

@ProthamD ProthamD closed this May 19, 2026
@ProthamD
ProthamD deleted the fix/shell-sighup-wsl2-bun-issue-16248 branch May 19, 2026 20:00
@sripasg sripasg added the size/m A medium sized PR label Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core Issues related to User Interface, OS Support, Core Functionality help wanted We will accept PRs from all issues marked as "help wanted". Thanks for your support! priority/p1 Important and should be addressed in the near term. priority/p2 Important but can be addressed in a future release. size/m A medium sized PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

All Shell commands fail with "Command terminated by signal: 1"

2 participants