# Command injection by overwriting authorized_keys file through GitLab import

GitLab import path parameter allowed directory traversal to overwrite git user's authorized_keys, yielding arbitrary command execution via SSH.

- Payout: $2,000
- Severity: critical
- Program: GitLab
- Credited: jobert
- Disclosed: 2018-04-27
- CVE: CVE-2017-0915
- Write-up quality: 8/10
- Original: https://hackerone.com/reports/298873
- Library page: https://bugbountylibrary.com/r/h1%3A298873
- Tags: domain:web impact:internal-access impact:rce kind:bounty platform:hackerone sev:critical tech:ruby technique:source-review vuln:command-injection vuln:path-traversal vuln:rce

**Target:** GitLab project import endpoint (/import/gitlab_project)
**Root cause:** GitlabProjectsImportService builds import_upload_path from unsanitized params[:path] and copies attacker-controlled file contents there, allowing path traversal and arbitrary file write.
**Steps:**
1. Authenticate to GitLab with import enabled
2. POST /import/gitlab_project with multipart fields path, namespace_id, file
3. Set path to `new-test/../../../../../../../../../var/opt/gitlab/.ssh/authorized_keys`
4. Set file body to `command="<cmd>",no-port-forwarding,... ssh-rsa <attacker pubkey>`
5. Send request; 302 returned but file persists
6. Run `ssh git@gitlab-instance` to execute command
**How found:** Noticed import_upload_path concatenates unsanitized params[:path] and file contents are unverified; tried ERB view write (blocked by permissions), then enumerated writable paths under /var/opt/gitlab and found .ssh/authorized_keys writable by git.
**Exploitation:** Attacker uploads a crafted import archive whose contents are an SSH authorized_keys entry with a forced command and their public key, written via traversal into /var/opt/gitlab/.ssh/authorized_keys. Connecting over SSH as git triggers the forced command, executing arbitrary commands as the git user with access to repos, DB, and secrets.
**Escalation:** Initial attempt to write ERB template into Rails views failed due to permissions; pivoted to writable .ssh/authorized_keys owned by git user for RCE.
**Insight:** When arbitrary file write exists, enumerate ownership/permissions of sensitive dotfiles (authorized_keys, cron, configs) rather than only app code paths; failed persistence via app views doesn't mean the write primitive is useless.
