google-gemini / google-gemini/gemini-cli

security(core): project .env can inject execution-affecting GIT_* variables (GIT_EXEC_PATH, GIT_SSH_COMMAND, GIT_PROXY_COMMAND) into internal git operations; sanitization only strips GIT_CONFIG_*

Open
#29,003 1 comment 0 reactions 0 assignees View on GitHub
area/security kind/bug priority/p1 status/manual-triage
Dominant language
TypeScript
Stars
107k
Forks
14.6k
Avg merge
2d 3h
Merged PRs (30d)
45

Description

### What happened?

Gemini CLI loads a project's `.env` file into `process.env` at startup (trusted workspaces load **all** keys), and its internal git operations are executed with an environment derived from `process.env`. The git-environment hardening that does exist (`getSafeGitEnv()` in `packages/core/src/utils/gitUtils.ts`, `sanitizeEnvironment()` usage in `packages/core/src/services/gitService.ts`, and the equivalent logic in `shellExecutionService.prepareExecution`) only neutralizes `GIT_CONFIG_*` / `GIT_CONFIG_PARAMETERS`. It does not touch the other `GIT_*` variables that change *which binaries and helpers git executes*.

As a result, a malicious-but-trusted repository can ship a `.env` containing, for example:

```env
GIT_EXEC_PATH=C:\Users\victim\AppData\Local\Temp\evil
GIT_SSH_COMMAND=calc.exe
GIT_PROXY_COMMAND=cmd /c calc.exe
```

and, merely by starting Gemini CLI inside that repository (folder-trusted, e.g. once via the trust prompt or when folder trust is disabled), trigger attacker-controlled code through completely ordinary, non-model, pre-approval git calls such as:

- checkpointing initialization — `GitService.initialize()` → `spawnAsync('git', ['--version'], { env: getSafeGitEnv() })` and subsequent shadow-repo commits (git resolves subcommand binaries from `GIT_EXEC_PATH`; `core.hooksPath` is already neutralized, but these env vectors are not)
- extension install/update — `cloneFromGit()` uses `simple-git` with `getSafeGitEnv()`, where `git.fetch`/`clone` will invoke `GIT_SSH_COMMAND`/`GIT_PROXY_COMMAND` for non-https remotes
- memory/git integration paths using `getAbsoluteGitDir()`

The codebase demonstrates awareness of this exact risk class: `DEFAULT_EXCLUDED_ENV_VARS` blocks `GEMINI_CLI_IDE_SERVER_STDIO_COMMAND`/`_ARGS` from project env files precisely because they name executables — but no equivalent protection exists for git's executable/helper env vars.

### What did you expect to happen?

Environment sanitization for internal git invocations should also strip or pin execution-affecting variables, e.g.:

- In `getSafeGitEnv()` (and the parallel logic in `gitService.getShadowRepoEnv()` / `shellExecutionService.prepareExecution`): delete `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` (as applicable), rather than only `GIT_CONFIG_*`.
- Alternatively/additionally, extend `DEFAULT_EXCLUDED_ENV_VARS` so project `.env` files cannot introduce these variables at all.

This restores the same isolation intent that already exists for git config (credential.helper, core.hooksPath, etc.) but which currently stops one layer short.

### Client information

Source-level finding verified against upstream `main` at commit `5411f113c`. All platforms; requires a trusted workspace whose `.env` sets the offending variables (untrusted workspaces are protected because `loadEnvironment()` whitelists only `GEMINI_API_KEY`, `GOOGLE_API_KEY`, `GOOGLE_CLOUD_PROJECT`, `GOOGLE_CLOUD_LOCATION`).

### Login information

Not applicable.

### Anything else we need to know?

Sources:

- `packages/cli/src/config/settings.ts:693-726` — trusted workspace `.env` values are loaded into `process.env` unless in `DEFAULT_EXCLUDED_ENV_VARS`
- `packages/cli/src/config/settings.ts:82-87` — `DEFAULT_EXCLUDED_ENV_VARS` contains only 4 entries; no `GIT_*`
- `packages/core/src/utils/gitUtils.ts:9-45` — `getSafeGitEnv()` strips only `GIT_CONFIG_*`/`GIT_CONFIG_PARAMETERS`
- `packages/core/src/services/gitService.ts:102-124` — shadow-repo env built from sanitized `process.env`; execution-affecting `GIT_*` survive
- `packages/cli/src/config/extensions/github.ts:37` — extension clones run with `getSafeGitEnv()`
- Related but distinct: #28684 (env-var load-order race affecting settings resolution) — different defect.
- Duplicate check: searched issues/PRs for "GIT_EXEC_PATH", "GIT_SSH_COMMAND", "safe git env" — no existing report or fix found.

Contributor guide

Open the contributing guide

Research direction

Start with getSafeGitEnv() in packages/core/src/utils/gitUtils.ts, then compare the parallel environment handling in packages/core/src/services/gitService.ts and shellExecutionService.prepareExecution. Review DEFAULT_EXCLUDED_ENV_VARS and trusted .env loading in packages/cli/src/config/settings.ts, plus extension cloning in packages/cli/src/config/extensions/github.ts. Done means execution-affecting GIT_* variables from project environments no longer reach internal git operations while ordinary git behavior remains supported.

Written by the indexing model from the issue text.

Assessment

Tech stack
git, typescript
Domain
cli, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
58/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.