Last pipeline status leaked for MRs via MR widget

HackerOne report #638494 by xanbanx on 2019-07-09:

Summary

GitLab has the feature to disable pipelines for non-project members on public project. The intend here is that only project members are granted to access the pipeline information. However, the last pipeline status of a build of an associated merge request is leaked via the JSON data for the merge request widget.

Steps to reproduce

  1. Create a public project, set Pipelines visibility to project members only, and disable public pipelines
  2. Push something to the repo such that CI is working, e.g., just the BASH gitlab-ci.yml example file
  3. Push some changes and create a merge request
  4. As a non-project member perform the following GET request: https://example.gitlab.com/<namespace>/<project>/merge_requests/1/widget.json Since merge requests are available for public users, this will return a JSON response like the following:
{
    "id": 32300194,  
    "iid": 1,  
    "description": "Closes #1 ",  
    "title": "Update README.md",  
    "approvals_before_merge": 0,  
    "blob_path": {  
        "head_path": "/wter23/project-with-mr/blob/848b46959a474e964baa592275b8bfd9e66e7f2f"  
    },  
    "pipeline_id": 70161693,  
    "vulnerability_feedback_path": "/wter23/project-with-mr/vulnerability_feedback",  
    "create_vulnerability_feedback_issue_path": null,  
    "create_vulnerability_feedback_merge_request_path": null,  
    "create_vulnerability_feedback_dismissal_path": null,  
    "rebase_commit_sha": null,  
    "rebase_in_progress": false,  
    "merge_pipelines_enabled": false,  
    "merge_trains_enabled": false,  
    "can_push_to_source_branch": false,  
    "has_approvals_available": true,  
    "rebase_path": null,  
    "approvals_path": "/wter23/project-with-mr/merge_requests/1/approvals",  
    "api_approvals_path": "/api/v4/projects/13062357/merge_requests/1/approvals",  
    "api_approval_settings_path": "/api/v4/projects/13062357/merge_requests/1/approval_settings",  
    "api_approve_path": "/api/v4/projects/13062357/merge_requests/1/approve",  
    "api_unapprove_path": "/api/v4/projects/13062357/merge_requests/1/unapprove",  
    "blocking_merge_requests": {  
        "total_count": 0,  
        "hidden_count": 0,  
        "visible_merge_requests": {}  
    },  
    "state": "opened",  
    "in_progress_merge_commit_sha": null,  
    "merge_commit_sha": null,  
    "short_merge_commit_sha": null,  
    "merge_error": null,  
    "merge_params": {  
        "force_remove_source_branch": "1"  
    },  
    "merge_status": "can_be_merged",  
    "merge_user_id": null,  
    "auto_merge_enabled": false,  
    "auto_merge_strategy": null,  
    "available_auto_merge_strategies": [],  
    "source_branch": "test",  
    "source_branch_protected": false,  
    "source_project_id": 13062357,  
    "source_project_full_path": "wter23/project-with-mr",  
    "squash": false,  
    "target_branch": "master",  
    "target_branch_sha": "7f6f7d7094b3e5becfa5091ecae5eb7b0e92d8ce",  
    "target_project_id": 13062357,  
    "target_project_full_path": "wter23/project-with-mr",  
    "allow_collaboration": false,  
    "should_be_rebased": false,  
    "ff_only_enabled": false,  
    "metrics": null,  
    "merge_user": null,  
    "diff_head_sha": "848b46959a474e964baa592275b8bfd9e66e7f2f",  
    "default_squash_commit_message": "Update README.md",  
    "default_merge_commit_message": "Merge branch 'test' into 'master'\n\nUpdate README.md\n\nCloses #1\n\nSee merge request wter23/project-with-mr!1",  
    "default_merge_commit_message_with_description": "Merge branch 'test' into 'master'\n\nUpdate README.md\n\nCloses #1 \n\nSee merge request wter23/project-with-mr!1",  
    "commits_without_merge_commits": [  
        {  
            "message": "Add new file",  
            "short_id": "848b4695",  
            "title": "Add new file"  
        },  
        {  
            "message": "Update README.md",  
            "short_id": "06121f78",  
            "title": "Update README.md"  
        }  
    ],  
    "commits_count": 2,  
    "merge_ongoing": false,  
    "work_in_progress": false,  
    "source_branch_exists": true,  
    "mergeable_discussions_state": true,  
    "branch_missing": false,  
    "has_conflicts": false,  
    "can_be_merged": true,  
    "mergeable": true,  
    "remove_source_branch": true,  
    "project_archived": false,  
    "only_allow_merge_if_pipeline_succeeds": false,  
    "has_ci": true,  
    "ci_status": "success",  
    "source_branch_with_namespace_link": "<a href=\"/wter23/project-with-mr/tree/test\">test</a>",  
    "source_branch_path": "/wter23/project-with-mr/-/branches/test",  
    "current_user": {  
        "can_remove_source_branch": false,  
        "can_revert_on_current_merge_request": false,  
        "can_cherry_pick_on_current_merge_request": false,  
        "can_create_note": false,  
        "can_create_issue": false,  
        "can_update": false  
    },  
    "target_branch_commits_path": "/wter23/project-with-mr/commits/master",  
    "target_branch_tree_path": "/wter23/project-with-mr/tree/master",  
    "new_blob_path": null,  
    "conflict_resolution_path": null,  
    "remove_wip_path": null,  
    "cancel_auto_merge_path": null,  
    "create_issue_to_resolve_discussions_path": null,  
    "merge_path": null,  
    "cherry_pick_in_fork_path": null,  
    "revert_in_fork_path": null,  
    "email_patches_path": "/wter23/project-with-mr/merge_requests/1.patch",  
    "plain_diff_path": "/wter23/project-with-mr/merge_requests/1.diff",  
    "merge_request_basic_path": "/wter23/project-with-mr/merge_requests/1.json?serializer=basic",  
    "merge_request_widget_path": "/wter23/project-with-mr/merge_requests/1/widget.json",  
    "ci_environments_status_path": "/wter23/project-with-mr/merge_requests/1/ci_environments_status",  
    "diverged_commits_count": 0,  
    "create_note_path": "/wter23/project-with-mr/notes?target_id=32300194&target_type=merge_request",  
    "commit_change_content_path": "/wter23/project-with-mr/merge_requests/1/commit_change_content",  
    "preview_note_path": "/wter23/project-with-mr/preview_markdown?target_id=1&target_type=MergeRequest",  
    "merge_commit_path": null,  
    "test_reports_path": null,  
    "can_receive_suggestion": true,  
    "conflicts_docs_path": "/help/user/project/merge_requests/resolve_conflicts.md",  
    "merge_request_pipelines_docs_path": "/help/ci/merge_request_pipelines/index.md"  
}

Here you see in the response the field ci_status leaking the CI status of the merge request. Furthermore, also the pipeline ID is leaking, but this is very minor.

Impact

See below.

Examples

This happens on gitlab.com. You can see this at https://gitlab.com/wter23/project-with-mr/merge_requests/1/widget.json.

What is the current bug behavior?

CI status and pipeline ID are leaked to unauthorized users.

What is the expected correct behavior?

Do not expose the pipeline ID and CI status to users, which do not have access to the pipeline information.

Best regards,
Xanbanx

Impact

Unauthorized users, who can read merge request have access to the CI status information of this merge request. Any user, who does have merge request permission can iterate over all merge requests and can query the CI status information.

Proposal for the fix

#29992 (comment 286945114)

Edited Feb 12, 2020 by Fabio Pitino
Assignee Loading
Time tracking Loading