# GitLab CI runner can read and poison cache of all other projects

GitLab CI runner cache key lacked sanitization, letting any user path-traverse to read and poison other projects' shared cache ZIPs, enabling arbitrary code execution in victim pipelines.

- Payout: $2,000
- Severity: critical
- Program: GitLab
- Credited: jobert
- Disclosed: 2018-04-27
- CVE: CVE-2017-0918
- Write-up quality: 8/10
- Original: https://hackerone.com/reports/301432
- Library page: https://bugbountylibrary.com/r/h1%3A301432
- Tags: domain:cloud impact:data-leak impact:integrity impact:rce kind:bounty platform:hackerone sev:critical tech:docker technique:chained vuln:path-traversal vuln:rce

**Target:** GitLab CI runner shared cache (runners-cache-N-internal.gitlab.com:444)
**Root cause:** The cache `key` from .gitlab-ci.yml is concatenated into the cache download/upload URL path without sanitization, so `../` sequences traverse out of the project's cache namespace on the shared cache server.
**Steps:**
1. Create project with `.gitlab-ci.yml` using `cache: {key: ../1/cache, policy: pull, paths: [.]}` and a script running `ls -lashR`
2. Run pipeline; runner requests `http://runners-cache-4-internal.gitlab.com:444/runner/gitlab/project/1/cache` instead of own project ID
3. Observe other project's cache contents in build output; exfiltrate via `cat` or build artifacts
4. To poison: set `cache: {key: ../1/cache, policy: push, paths: [file-to-poison]}` and `echo 1 > file-to-poison`, then run pipeline
5. Victim project's next CI run downloads the poisoned cache and uses attacker-controlled files (e.g. overwrite `13083/ruby-235-with-yarn` Ruby executable)
**How found:** Noticed dedicated runners still used shared cache hosts (runners-cache-3/4-internal), suspected design flaw; tried reaching cache servers from a Docker reverse shell (failed), then reasoned the cache key is embedded in the HTTP URL path and tested `../` traversal in the key.
**Exploitation:** Attacker with any GitLab account creates a project and pipeline; the runner builds the cache URL from the unsanitized key, traversing to another project's cache path. Pull policy reads victim cache into the working dir for exfiltration; push policy overwrites victim cache entries with attacker files, which the victim runner then extracts and executes, yielding code execution in the victim's Docker CI container.
**Escalation:** Enumerate project IDs (auto-incremental) and guessable cache keys (often step names or unused) to target many projects; overwrite cached executables to gain RCE across pipelines.
**Insight:** When a user-controlled field is interpolated into a URL path for a shared backend (cache, artifact, storage), test `../` traversal in that field to cross tenant namespaces; also check whether 'dedicated' runners still share a common cache host.
