Productivity analytics endpoint doesn't enforce properly tier check

HackerOne report #707375 by rpadovani on 2019-10-03, assigned to @cmaxim:

Summary

The new Productivity Analytics feature should be available only to Premium or higher accounts.

The endpoint to retrieve data for the feature, however, doesn't properly authenticate the user, allowing any user to retrieve the data, making the feature easily available to anyone.

However, there isn't any leak of confidential data, because the users retrieve only data that they could already retrieve, if they had paid.

It is just an unauthorized access to paid resources.

Steps to reproduce

  1. The endpoint /-/analytics/productivity_analytics, when queried for a JSON reply using the Accept header, returns data in the JSON format. If you do not specify anything, it returns the HTML page.
  2. The endpoint authenticates the parameter group_id and project_id. That is, it checks the group or the project has at least a premium license.
  3. If you do not specify nor the group_id or the project_id, the endpoint just executes the query.
  4. In this way, you can access all the data needed to do the analytics. You can also access public data of other projects that are not usually easily accessible.
  5. Since a lot of parameters are accepted, it is easy to customize the search to return only the MR of a project that is not under the premium license. E.g: using the my_reaction_emoji parameter.

Here the list of accepted parameters:

  • scope: 'created_by_me' or 'assigned_to_me' or 'all'  
  • state: 'open', 'closed', 'merged', 'locked', or 'all'  
  • milestone_title: string  
  • author_id: integer  
  • assignee_id: integer  
  • search: string  
  • in: 'title', 'description', or a string joining them with comma  
  • label_name: string  
  • sort: string  
  • non_archived: boolean  
  • my_reaction_emoji: string  
  • source_branch: string  
  • target_branch: string  
  • created_after: datetime  
  • created_before: datetime  
  • updated_after: datetime  
  • updated_before: datetime

Impact

Users can access a premium feature for free without any difficulty (a proxy or a browser plugin would work well enough)

Examples

This is an example of a fetch request made from the console, so with the cookies:

 a = await fetch("https://gitlab.com/-/analytics/productivity_analytics?scope=created_by_me", {  
    "credentials": "include",  
    "headers": {  
        "Accept": "application/json, text/plain, */*",  
        "X-CSRF-Token": "token",  
        "X-Requested-With": "XMLHttpRequest"  
    },  
    "referrer": "https://gitlab.com/-/analytics/productivity_analytics",  
    "method": "GET",  
    "mode": "cors"  
});  
await a.json()  

The response is an array of 20 objects with all the data needed by the feature

What is the current bug behavior?

I can query the productivity_analytics endpoint without specifying group_id nor project_id

What is the expected correct behavior?

group_id or project_id are required, and they are used to check I am allowed to access the resource

Output of checks

This bug happens on GitLab.com

Impact

Users can access a premium feature for free without any difficulty (a proxy or a browser plugin would work well enough)

Assignee Loading
Time tracking Loading