Draft: Add content type allowlist and return generic package file with the content type

What does this MR do and why?

Currently, when user uploads a generic package file, the system will store the file in object storage as binary/octet-stream in MinIO and when users try to (for example) get a css file via a html page, because of the wrong content type, the browser will stop the file from being downloaded.

In the previous MR, we found a security concern that if we just return the file with the correct content types, it may lead to XSS attacks. For example, if a user uploads a malicious JavaScript file to the generic package registry and we serve it with content-type: application/javascript, the browser will execute the script when it's loaded (e.g., via <script src="...">), potentially allowing XSS attacks. Currently, serving it as binary/octet-stream prevents the browser from executing it as JavaScript.

After some discussions, we decided to create a allowlist of content types, and only return the specific content-type in header when it's allowed.

We've collected all the possible content types and this MR will start use the defined allowlist and return generic package file with allowed content-type when feature flag packages_generic_package_content_type_allowlist is enabled.

References

Screenshots or screen recordings

N/A

How to set up and validate locally

  1. Switch to this branch 552990-return-generic-package-file-with-content-type

  2. Open another tab and create a new folder

  3. Create test css file

    body {
        background-color: #f0f0f0;
        font-family: Arial, sans-serif;
        color: #333;
    }
    .test-element {
        background-color: #007bff;
        color: white;
        padding: 10px;
        border-radius: 5px;
    }
  4. Upload CSS file to generic package registry

    curl --location -v \
        --header "PRIVATE-TOKEN: ${TOKEN}" \
        --upload-file test_css.css \
        "${GITLAB_URL}/api/v4/projects/${PROJECT_ID}/packages/generic/test-generic-package/2.3.3/test_css.css"
  5. Download css file and check the header

    curl -I --header "PRIVATE-TOKEN: ${TOKEN}" \
        "${GITLAB_URL}/api/v4/projects/${PROJECT_ID}/packages/generic/test-generic-package/2.3.3/test_css.css"
    
    ...
    Content-Type: application/octet-stream
    ...
  6. Enter rails console and enabled the feature flag

    Feature.enable(:packages_generic_package_content_type_allowlist)
  7. Download the css again, the header Content-Type should be proper returned

    curl -I --header "PRIVATE-TOKEN: ${TOKEN}" \
        "${GITLAB_URL}/api/v4/projects/${PROJECT_ID}/packages/generic/test-generic-package/2.3.3/test_css.css"
    
    ...
    Content-Type: text/css
    ...

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Related to #552990

Merge request reports

Loading