# SSRF in CI after first run

GitLab CI runners blocked SSRF to cloud metadata on first pipeline run but allowed it on re-run, exposing DigitalOcean metadata endpoints to any CI job.

- Payout: hidden
- Severity: medium
- Program: GitLab
- Found by: plazmaz
- Disclosed: 2019-04-12
- Write-up quality: 6/10
- Original: https://hackerone.com/reports/369451
- Library page: https://bugbountylibrary.com/r/h1%3A369451
- Tags: area:cloud domain:cloud domain:infra impact:data-leak impact:internal-access kind:bounty platform:hackerone sev:medium tech:ci-cd technique:regression vuln:misconfiguration vuln:ssrf

**Target:** GitLab CI runner / cloud instance metadata endpoint
**Root cause:** CI runner network restrictions against link-local metadata (169.254.169.254) were applied on the first pipeline run but not enforced on subsequent re-runs, leaving the metadata service reachable from the job container.
**Steps:**
1. Create a `.gitlab-ci.yml` with a job that runs a shell script.
2. Script contains `curl -L http://169.254.169.254/metadata/v1/`.
3. Run the pipeline once: request is blocked, no leak.
4. Re-run the same pipeline: the curl now returns DigitalOcean metadata listing (id, hostname, user-data, public-keys, region, interfaces/, dns/, etc.).
**How found:** Researcher noticed the first CI run blocked the metadata request but suspected the restriction was stateful; re-running the same build showed the SSRF succeeded, indicating the defense was only applied on initial runs.
**Exploitation:** A user able to push a `.gitlab-ci.yml` runs a job that curls the link-local metadata endpoint; on the second run the response leaks instance metadata (hostname, user-data, public keys, region, network interfaces) usable for further internal access.
**Insight:** When a platform blocks SSRF on first execution, test stateful re-execution paths (re-runs, retries, cached jobs) — defenses applied only at provisioning time often don't persist to subsequent runs of the same job.

