Skip to content

fix(core): strip execution-affecting GIT_* env vars in getSafeGitEnv - #29008

Open
chelsealong wants to merge 3 commits into
google-gemini:mainfrom
chelsealong:fix/git-safe-env-execution-vars-29003
Open

fix(core): strip execution-affecting GIT_* env vars in getSafeGitEnv#29008
chelsealong wants to merge 3 commits into
google-gemini:mainfrom
chelsealong:fix/git-safe-env-execution-vars-29003

Conversation

@chelsealong

Copy link
Copy Markdown

Summary

Fixes #29003.

Gemini CLI loads a trusted project's .env file into process.env. The
issue names three internal call sites that route git operations through an
environment derived from process.env, and reports that all three only
strip GIT_CONFIG_* / GIT_CONFIG_PARAMETERS, leaving execution-affecting
GIT_* variables such as GIT_EXEC_PATH, GIT_SSH_COMMAND, and
GIT_PROXY_COMMAND to pass straight through:

  • getSafeGitEnv() in packages/core/src/utils/gitUtils.ts
  • GitService.getShadowRepoEnv() (already chains into getSafeGitEnv())
  • ShellExecutionService.prepareExecution() in
    packages/core/src/services/shellExecutionService.ts, which builds its
    own environment via sanitizeEnvironment() and does not call
    getSafeGitEnv() at all

A trusted-but-malicious repository could ship a .env setting these
variables and get arbitrary code execution the moment Gemini CLI ran any
ordinary, non-model git call (checkpointing, worktrees, extension
install/update, grep's git ls-files fallback) or any ordinary shell
command that happens to invoke git (e.g. git status) — no explicit user
approval step involved.

This PR extends sanitization in both places:

  1. getSafeGitEnv() now also strips:

    • GIT_EXEC_PATH
    • GIT_PROXY_COMMAND
    • GIT_SSH_COMMAND
    • GIT_SSH_VARIANT
    • GIT_ALTERNATE_OBJECT_DIRECTORIES
    • GIT_TEMPLATE_DIR
    • GIT_REPLACE_REF_BASE
    • GIT_CEILING_DIRECTORIES

    GitService.getShadowRepoEnv(), extension install/update, and grep's
    git fallback all route through this function, so they're covered
    transitively.

  2. ShellExecutionService.prepareExecution() now deletes the same set of
    variables (exported from gitUtils.ts as
    EXECUTION_AFFECTING_GIT_ENV_VARS) from the environment it builds for
    every shell command, closing the gap for the shell-execution path.

Test plan

Added packages/core/src/utils/gitUtils.test.ts, asserting the vars above
are stripped from getSafeGitEnv()'s returned environment while unrelated
variables (e.g. PATH) and the existing GIT_CONFIG_* stripping behavior
are preserved.

Added a test to packages/core/src/services/shellExecutionService.test.ts
("should strip execution-affecting GIT_* variables from the spawned
environment") asserting the same variables are absent from the environment
passed to child_process.spawn, while unrelated variables (e.g. PATH)
are preserved. This test explicitly unsets GITHUB_SHA/SURFACE so it
exercises the default (non-strict) sanitization path — the actual
vulnerable path for ordinary local usage — rather than being masked by the
stricter CI-only sanitization mode.

Confirmed both new tests fail without their respective source fix:

❯ src/utils/gitUtils.test.ts (2 tests | 1 failed)
   × getSafeGitEnv > strips execution-affecting GIT_* variables from the base environment
     → expected '/tmp/evil' to be undefined
   ✓ getSafeGitEnv > still strips GIT_CONFIG_* variables from the base environment
❯ src/services/shellExecutionService.test.ts (70 tests | 1 failed)
   × ShellExecutionService environment variables > should strip execution-affecting GIT_* variables from the spawned environment
     → expected { Object (...) } to not have property "GIT_EXEC_PATH"

And both pass with their fixes restored (150/150 across the directly
related suites):

npx vitest run src/services/shellExecutionService.test.ts src/utils/gitUtils.test.ts \
  src/services/gitService.test.ts src/services/worktreeService.test.ts src/tools/grep.test.ts
# 5 files, 150 tests passed

Also ran the full core package test suite:

npm run test:ci -w @google/gemini-cli-core
# 7815 passed, 53 skipped, 19 failed (all in sandboxManager.integration.test.ts)

The 19 failures are pre-existing and unrelated to this change: they
require the bwrap (bubblewrap) sandbox binary, which is not installed in
this environment.

Also ran npm run lint (repo-wide, --max-warnings 0) and
tsc --noEmit for packages/core — both clean.

AI assistance disclosure

This change was implemented with AI assistance (an autonomous Claude-based
coding agent), with the diff, tests, and test output reviewed before
submission.

Project .env files loaded into process.env for trusted workspaces can set
GIT_EXEC_PATH, GIT_SSH_COMMAND, GIT_PROXY_COMMAND, and similar variables
that control which binaries/helpers git executes. getSafeGitEnv() only
stripped GIT_CONFIG_* variables, so these leaked through to every internal
git invocation (checkpointing, worktrees, extension installs, grep's git
ls-files usage), letting a malicious-but-trusted repo run arbitrary
commands via ordinary git calls.

Fixes google-gemini#29003
…ice too

getSafeGitEnv() covers internal git operations (checkpointing, worktrees,
extension installs, grep's git fallback), but ordinary shell commands run
through ShellExecutionService.prepareExecution(), which builds its own
environment via sanitizeEnvironment() and never routes through
getSafeGitEnv(). Since default (non-strict) sanitization leaves GIT_* vars
untouched, a trusted-but-malicious project .env could still set
GIT_EXEC_PATH/GIT_SSH_COMMAND/etc. and get them inherited by any shell
command that happens to invoke git (e.g. `git status`), per google-gemini#29003's third
named vector. This strips the same execution-affecting GIT_* vars from the
shell-execution environment.
@chelsealong
chelsealong requested a review from a team as a code owner August 24, 2026 12:11
@github-actions github-actions Bot added the size/m A medium sized PR label Aug 24, 2026
@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown

📊 PR Size: size/M

  • Lines changed: 141
  • Additions: +139
  • Deletions: -2
  • Files changed: 4

@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 security vulnerability where Git-related environment variables could be exploited to achieve arbitrary code execution. By ensuring that specific GIT_* variables are stripped from the environment before executing Git commands or spawning shell processes, the changes mitigate the risk posed by trusted-but-malicious project configurations.

Highlights

  • Enhanced Git Environment Sanitization: Updated getSafeGitEnv to strip additional execution-affecting GIT_* environment variables, preventing potential arbitrary code execution from malicious .env files.
  • Shell Execution Security: Extended environment sanitization in ShellExecutionService.prepareExecution to explicitly remove the same set of dangerous Git variables for all spawned shell commands.
  • Comprehensive Testing: Added new unit tests in gitUtils.test.ts and shellExecutionService.test.ts to verify that the identified dangerous variables are correctly stripped while preserving legitimate environment variables.
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.

@gemini-cli gemini-cli Bot added priority/p1 Important and should be addressed in the near term. area/security Issues related to security labels Aug 24, 2026

@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 security enhancements by stripping execution-affecting GIT_* environment variables (such as GIT_EXEC_PATH and GIT_SSH_COMMAND) from the environment before executing shell commands, preventing potential arbitrary command execution from malicious repositories. Corresponding unit tests have been added to verify this behavior. The review feedback highlights two important improvements: first, adding GIT_CONFIG_PARAMETERS to the list of stripped variables to close a potential command injection vector, and second, updating the test file to use an empty string instead of undefined when unsetting environment variables with vi.stubEnv to align with the repository's testing conventions.

Comment on lines +15 to +24
export const EXECUTION_AFFECTING_GIT_ENV_VARS = new Set([
'GIT_EXEC_PATH',
'GIT_PROXY_COMMAND',
'GIT_SSH_COMMAND',
'GIT_SSH_VARIANT',
'GIT_ALTERNATE_OBJECT_DIRECTORIES',
'GIT_TEMPLATE_DIR',
'GIT_REPLACE_REF_BASE',
'GIT_CEILING_DIRECTORIES',
]);

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 EXECUTION_AFFECTING_GIT_ENV_VARS set defines the list of git environment variables that are stripped from the environment before executing shell commands to prevent arbitrary command execution. However, it does not include GIT_CONFIG_PARAMETERS.

In shellExecutionService.ts, all environment variables starting with GIT_CONFIG_ (which includes GIT_CONFIG_PARAMETERS) are explicitly collected and preserved in the execution environment. Since GIT_CONFIG_PARAMETERS is not stripped, a malicious repository could supply a .env file containing GIT_CONFIG_PARAMETERS (e.g., setting core.pager or core.sshCommand to a malicious executable), leading to arbitrary code execution when Gemini CLI runs any shell command that invokes git.

To remediate this, add 'GIT_CONFIG_PARAMETERS' to the EXECUTION_AFFECTING_GIT_ENV_VARS set.

Suggested change
export const EXECUTION_AFFECTING_GIT_ENV_VARS = new Set([
'GIT_EXEC_PATH',
'GIT_PROXY_COMMAND',
'GIT_SSH_COMMAND',
'GIT_SSH_VARIANT',
'GIT_ALTERNATE_OBJECT_DIRECTORIES',
'GIT_TEMPLATE_DIR',
'GIT_REPLACE_REF_BASE',
'GIT_CEILING_DIRECTORIES',
]);
export const EXECUTION_AFFECTING_GIT_ENV_VARS = new Set([
'GIT_EXEC_PATH',
'GIT_PROXY_COMMAND',
'GIT_SSH_COMMAND',
'GIT_SSH_VARIANT',
'GIT_ALTERNATE_OBJECT_DIRECTORIES',
'GIT_TEMPLATE_DIR',
'GIT_REPLACE_REF_BASE',
'GIT_CEILING_DIRECTORIES',
'GIT_CONFIG_PARAMETERS',
]);

Comment on lines +2274 to +2275
vi.stubEnv('GITHUB_SHA', undefined);
vi.stubEnv('SURFACE', undefined);

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

According to the repository's testing conventions, to "unset" an environment variable when using vi.stubEnv, you should use an empty string '' instead of undefined to avoid potential test leakage or unexpected behavior in Vitest.

Suggested change
vi.stubEnv('GITHUB_SHA', undefined);
vi.stubEnv('SURFACE', undefined);
vi.stubEnv('GITHUB_SHA', '');
vi.stubEnv('SURFACE', '');
References
  1. When testing code that depends on environment variables, use vi.stubEnv('NAME', 'value') and to 'unset' a variable, use an empty string vi.stubEnv('NAME', '').

GIT_CONFIG_PARAMETERS was preserved by shellExecutionService's
GIT_CONFIG_* allow list but not stripped by
EXECUTION_AFFECTING_GIT_ENV_VARS, letting a malicious .env set
core.sshCommand/core.pager via that variable. Also switch the
GITHUB_SHA/SURFACE test stubs to '' per repo convention for vi.stubEnv.
@chelsealong

Copy link
Copy Markdown
Author

Addressed both review comments: added GIT_CONFIG_PARAMETERS to EXECUTION_AFFECTING_GIT_ENV_VARS in gitUtils.ts (it was otherwise re-preserved by shellExecutionService.ts's GIT_CONFIG_* allow list), and switched the GITHUB_SHA/SURFACE test stubs to '' per repo convention. Added a GIT_CONFIG_PARAMETERS case to the existing "strip execution-affecting GIT_* variables" test in shellExecutionService.test.ts, confirmed it fails without the fix and passes with it. Lint and full gitUtils/shellExecutionService test suites are clean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/security Issues related to security priority/p1 Important and should be addressed in the near term. size/m A medium sized PR

Projects

None yet

1 participant