Skip to content

A guest user is capable of bypassing API / UI restrictions and view dependency lists of private projects through job artifacts

Please read the process on how to fix security issues before starting to work on the issue. Vulnerabilities must be fixed in a security mirror.

HackerOne report #2189464 by ricardobrito on 2023-10-02, assigned to @ngeorge1:

Report | Attachments | How To Reproduce

Report

Summary

A guest user inside a group, by default is not allowed to view dependency lists, and if a guest user tries to access the dependency lists inside a private project in a group either through the UI or the API, the access controls do not allow him to do so (this is properly implemented). However, I have found a way for a guest user to access dependency lists of any private project of a group he is a member of, by using the job artifact that is created after the dependency scan.

Steps to reproduce
  1. As user A, create a public group, inside this group create a private project, say project A.
  2. As user A, inside project A, create the following 2 files:

requirements.txt

view content
###    
###  This file is autogenerated by pip-compile with python 3.10  
###  To update, run:  
###    
###     pip-compile  
###    
contourpy==1.0.6  
    # via matplotlib  
cycler==0.11.0  
    # via matplotlib  
fonttools==4.38.0  
    # via matplotlib  
kiwisolver==1.4.4  
    # via matplotlib  
matplotlib==3.6.2  
    # via  
    #   -r requirements.in  
    #   seaborn  
numpy==1.23.5  
    # via  
    #   -r requirements.in  
    #   contourpy  
    #   matplotlib  
    #   pandas  
    #   scipy  
    #   seaborn  
packaging==21.3  
    # via matplotlib  
pandas==1.5.1  
    # via  
    #   -r requirements.in  
    #   seaborn  
pillow==9.3.0  
    # via matplotlib  
pyparsing==3.0.9  
    # via  
    #   matplotlib  
    #   packaging  
python-dateutil==2.8.2  
    # via  
    #   matplotlib  
    #   pandas  
pytz==2022.6  
    # via pandas  
scipy==1.9.3  
    # via seaborn  
seaborn==0.10.1  
    # via -r requirements.in  
six==1.16.0  
    # via python-dateutil  

.gitlab-ci.yml

view content
include:  
  - template: Jobs/Dependency-Scanning.gitlab-ci.yml

build-job:  
  stage: build  
  script:  
    - echo "Hello, $GITLAB_USER_LOGIN!"

test-job1:  
  stage: test  
  script:  
    - echo "This job tests something new"

test-job2:  
  stage: test  
  script:  
    - echo "This job tests something, but takes more time than test-job1."  
    - echo "After the echo commands complete, it runs the sleep command for 20 seconds"  
    - echo "which simulates a test that runs 20 seconds longer than test-job1"  
    - sleep 20

deploy-prod:  
  stage: deploy  
  script:  
    - echo "This job deploys some stuff ( ... ) from the $CI_COMMIT_BRANCH branch."  
  environment: production  
  1. As user A, commit the changes so that the pipeline may run
  2. Still as user A, go to the project path and on the left side meny go to ** secure-> dependency lists ** and you should see a list of dependencies that were found after the ci job completed:

image.png

  1. As user A, invite another user, say User B to the group with guest priviledges.
  2. As user B, go to the project path and on the left side menu go to ** secure-> dependency lists ** and you will see the following:

image.png

This is correct behavior because the user only has guest permissions, and this is a private prject (the user cannot even see the code).

  1. As user B, inside the private project, go to ** build -> jobs** and select the job with the name ** gemnasium-python-dependency_scanning ** and on the right-side under job artifacts select browse and you will be taken to a job artifact which is a json file that contains the dependency list:

image.png

view content
{
  "bomFormat": "CycloneDX",  
  "specVersion": "1.4",  
  "serialNumber": "urn:uuid:24dfaf3c-57c8-420f-b4ee-5f637f11228f",  
  "version": 1,  
  "metadata": {  
    "timestamp": "2023-10-02T13:23:03Z",  
    "tools": [  
      {  
        "vendor": "GitLab",  
        "name": "Gemnasium",  
        "version": "4.4.7"  
      }  
    ],  
    "authors": [  
      {  
        "name": "GitLab",  
        "email": "support@gitlab.com"  
      }  
    ],  
    "properties": [  
      {  
        "name": "gitlab:dependency_scanning:input_file",  
        "value": "requirements.txt"  
      },  
      {  
        "name": "gitlab:dependency_scanning:input_file:path",  
        "value": "requirements.txt"  
      },  
      {  
        "name": "gitlab:dependency_scanning:package_manager",  
        "value": "pip"  
      },  
      {  
        "name": "gitlab:dependency_scanning:package_manager:name",  
        "value": "pip"  
      },  
      {  
        "name": "gitlab:meta:schema_version",  
        "value": "1"  
      }  
    ]  
  },  
  "components": [  
    {  
      "name": "Pillow",  
      "version": "9.3.0",  
      "purl": "pkg:pypi/Pillow@9.3.0",  
      "type": "library",  
      "bom-ref": "pkg:pypi/Pillow@9.3.0"  
    },  
    {  
      "name": "contourpy",  
      "version": "1.0.6",  
      "purl": "pkg:pypi/contourpy@1.0.6",  
      "type": "library",  
      "bom-ref": "pkg:pypi/contourpy@1.0.6"  
    },  
    {  
      "name": "cycler",  
      "version": "0.11.0",  
      "purl": "pkg:pypi/cycler@0.11.0",  
      "type": "library",  
      "bom-ref": "pkg:pypi/cycler@0.11.0"  
    },  
    {  
      "name": "fonttools",  
      "version": "4.38.0",  
      "purl": "pkg:pypi/fonttools@4.38.0",  
      "type": "library",  
      "bom-ref": "pkg:pypi/fonttools@4.38.0"  
    },  
    {  
      "name": "kiwisolver",  
      "version": "1.4.4",  
      "purl": "pkg:pypi/kiwisolver@1.4.4",  
      "type": "library",  
      "bom-ref": "pkg:pypi/kiwisolver@1.4.4"  
    },  
    {  
      "name": "matplotlib",  
      "version": "3.6.2",  
      "purl": "pkg:pypi/matplotlib@3.6.2",  
      "type": "library",  
      "bom-ref": "pkg:pypi/matplotlib@3.6.2"  
    },  
    {  
      "name": "numpy",  
      "version": "1.23.5",  
      "purl": "pkg:pypi/numpy@1.23.5",  
      "type": "library",  
      "bom-ref": "pkg:pypi/numpy@1.23.5"  
    },  
    {  
      "name": "packaging",  
      "version": "21.3",  
      "purl": "pkg:pypi/packaging@21.3",  
      "type": "library",  
      "bom-ref": "pkg:pypi/packaging@21.3"  
    },  
    {  
      "name": "pandas",  
      "version": "1.5.1",  
      "purl": "pkg:pypi/pandas@1.5.1",  
      "type": "library",  
      "bom-ref": "pkg:pypi/pandas@1.5.1"  
    },  
    {  
      "name": "pyparsing",  
      "version": "3.0.9",  
      "purl": "pkg:pypi/pyparsing@3.0.9",  
      "type": "library",  
      "bom-ref": "pkg:pypi/pyparsing@3.0.9"  
    },  
    {  
      "name": "python-dateutil",  
      "version": "2.8.2",  
      "purl": "pkg:pypi/python-dateutil@2.8.2",  
      "type": "library",  
      "bom-ref": "pkg:pypi/python-dateutil@2.8.2"  
    },  
    {  
      "name": "pytz",  
      "version": "2022.6",  
      "purl": "pkg:pypi/pytz@2022.6",  
      "type": "library",  
      "bom-ref": "pkg:pypi/pytz@2022.6"  
    },  
    {  
      "name": "scipy",  
      "version": "1.9.3",  
      "purl": "pkg:pypi/scipy@1.9.3",  
      "type": "library",  
      "bom-ref": "pkg:pypi/scipy@1.9.3"  
    },  
    {  
      "name": "seaborn",  
      "version": "0.10.1",  
      "purl": "pkg:pypi/seaborn@0.10.1",  
      "type": "library",  
      "bom-ref": "pkg:pypi/seaborn@0.10.1"  
    },  
    {  
      "name": "six",  
      "version": "1.16.0",  
      "purl": "pkg:pypi/six@1.16.0",  
      "type": "library",  
      "bom-ref": "pkg:pypi/six@1.16.0"  
    }  
  ]  
}

The contents are the same as the dependency list in the UI that the guest user was unable to access before.

The guest user does not have permission to access the dependency list in the UI but using this bypass he can have access to a complete list of dependencies of private projects (which he can not view the content of).

POC video

dependency-list-access-control.mov

Impact

A guest user is capable of accessing the dependency list of a private project inside a group, even though it is not allowed (due to his low permissions), by using job artifacts.

Attachments

Warning: Attachments received through HackerOne, please exercise caution!

How To Reproduce

Please add reproducibility information to this section:

Possible fixes

  1. highlight the risk of exposing data when enabling public pipelines
    1. add an alert notification for users with private projects and public pipelines enabled
    2. update the permissions documentation
  2. Add permissions check to restrict access to data exposed in CI jobs and artifact similarly to what we do in the GitLab UI
    1. when browsing or downloading artifacts
    2. when displaying/downloading CI job log output?
Edited by Olivier Gonzalez