In September 2022, a critical authorization flaw was disclosed and patched in GitLab, identified as CVE-2022-3706. This vulnerability impacts GitLab CE/EE versions:

and 15.5 prior to 15.5.2.

This bug allows a user—without permission on a target project—to take ownership of CI/CD jobs in an upstream pipeline by simply retrying a job in a downstream pipeline. Let’s walk through a real example and explain why this bug is serious, how to exploit it, and ways it could put organizations at risk.

What was the Bug?

GitLab CI/CD allows for pipelines to trigger other pipelines across different GitLab projects (so-called upstream and downstream pipelines). Normally, permissions are enforced so only allowed users can restart or “retry” failed jobs in projects they have access to. But due to improper authorization checks, a user with *downstream project* access could retry a job in the *downstream pipeline* and—by doing so—cause the equivalent upstream job (which they shouldn’t have access to) to be retried as their own user.

In plain language:  
A user can “become” the owner of retried jobs in another project pipeline they shouldn’t even *see*, just by clicking retry in their downstream pipeline.

Why Does This Matter?

- Confidential info leakage: Private data about upstream jobs becomes visible to unauthorized downstream users.
- Privilege escalation: If jobs do sensitive actions based on job owner/user tokens, someone could abuse this.
- Audit confusion: Job and artifact history will falsely show the unauthorized user as the acting operator of upstream jobs.

Project B: The downstream, public or shared project.

Project A’s pipeline triggers Project B’s pipeline after running initial jobs. CI/CD configs might look like this:

Project A (.gitlab-ci.yml)

stages:
  - test
  - deploy

test_job:
  stage: test
  script: echo "Tested!"

trigger_downstream:
  stage: deploy
  trigger:
    project: group/project-b
    strategy: depend

Project B (.gitlab-ci.yml)

stages:
  - build

build_job:
  stage: build
  script: echo "Building from downstream"

Step 2: Job Fails in Downstream

Suppose Project B's job fails. As a Project B member, you see the pipeline and the failed job.

Step 3: Retry the Downstream Job

You, as a Project B user (with *no* permissions on Project A), click “Retry” on the failed job in Project B.

Step 4: Trigger Upstream Job Ownership

Before patch:  
GitLab retried *both* the downstream and upstream jobs, but crucially, the *upstream job* (in Project A) was re-run with *your user as the owner*, even though you shouldn’t be able to interact with Project A at all.

If Project A’s job logs or artifacts leak secrets, you can now see or even download them.

- Audit logs in Project A show *your* user retried the job, even though you were never supposed to have access.

Here’s a simplified pseudo-code snippet to illustrate the problem

# Vulnerable logic
def retry_job(job, user)
  if user.can_access?(job.project) || job.pipeline.triggered_by?(user)
    job.retry!(as: user) # This doesn't double-check project permissions!
  end
end

But triggered_by? gives a pass via CI trigger chain.

After the patch, retried jobs require explicit project access, not mere involvement in a downstream chain.

References And More Info

- GitLab Security Advisory (archive)
- MITRE CVE-2022-3706 Page
- HackerOne report (not public, but similar issue)

15.5.2 or later.

If you’re stuck on an older version and can’t upgrade, minimize the use of cross-project pipeline triggers, and audit who has access to downstream projects.

Final Notes

CVE-2022-3706 taught the GitLab world an important lesson: cross-project jobs can become *hidden privilege escalations* if authentication is just slightly off. If you run CI/CD pipelines between private and public projects, make sure you’re not handing out the keys to your kingdom through chained job permissions!


Stay Updated:  
- GitLab official security blog
- GitLab release notes

Remember:  
If you find something similar, report it responsibly through GitLab’s bug bounty program. Happy (and safe) automating!

Timeline

Published on: 11/10/2022 00:15:00 UTC
Last modified on: 11/11/2022 01:43:00 UTC