# Local files could be overwritten in GitLab, leading to remote command execution

GitLab's directory-download feature passed a repo-controlled path to `git archive`; a directory named `--output=/var/opt/gitlab/.ssh/authorized_keys` made git write the tar to that file, injecting an SSH key for RCE.

- Payout: $12,000
- Severity: critical
- Program: GitLab
- Credited: saltyyolk
- Disclosed: 2019-07-17
- Write-up quality: 9/10
- Original: https://hackerone.com/reports/587854
- Library page: https://bugbountylibrary.com/r/h1%3A587854
- Tags: domain:web impact:integrity impact:rce kind:bounty platform:hackerone sev:critical tech:go technique:chained technique:source-review vuln:command-injection vuln:path-traversal vuln:rce

**Target:** Gitaly `git archive` invocation via GitLab repository directory download
**Root cause:** The user-controlled directory `path` was concatenated as a positional argument to `git archive` without `--` separator, so a path beginning with `--output=` was parsed as a git option rather than a pathspec.
**Steps:**
1. Create a repo containing a directory literally named `--output=/var/opt/gitlab/.ssh/authorized_keys/` with a file `id_ed25519.pub` holding your public key.
2. In the GitLab UI, browse to that directory and click 'download directory as tar'.
3. Gitaly runs `git --git-dir=DIR archive --format tar --prefix=/ COMMIT_ID --output=/var/opt/gitlab/.ssh/authorized_keys`, writing the tar to the target file.
4. Because tar is uncompressed, the embedded pubkey line survives inside the archive bytes; SSH ignores the surrounding tar headers.
5. `ssh -i ~/.ssh/id_ed25519 git@target` authenticates as the `git` user.
**How found:** Code review of the new archive feature in `internal/service/repository/archive.go` spotted the `path` parameter concatenated into the git command; hypothesis that a leading `--` would be interpreted as a git option, confirmed by crafting a directory named `--output=...`.
**Exploitation:** Attacker with repo write access crafts a malicious directory name to redirect git archive output to `/var/opt/gitlab/.ssh/authorized_keys`, embedding their SSH public key in the uncompressed tar stream, then SSHes in as the git user to gain RCE on the GitLab host.
**Escalation:** File overwrite of authorized_keys escalates to SSH login and command execution as the git service account.
**Insight:** When a user-controlled string is appended to a CLI invocation, test whether it can be parsed as an option (leading `--`); git's `--output` lets you redirect archive writes to arbitrary paths, and uncompressed tar preserves injected content past header garbage.
