Skip to content

Fix artifacts content-type

Max Orefice requested to merge morefice/fix-artifacts-content-type into master

Ref: https://gitlab.com/gitlab-org/gitlab/-/issues/214707

Description

This MR lets workhorse set the content-type when serving artifacts.

It uses http.DetectContentType and default to text/plain when necessary.

It lets workhorse sets the response header itself as decided with the team (this is the same technique used for git blobs) which default content type to text/plain.

API endpoints
Internal REST ArtifactsController#raw
External REST :id/jobs/artifacts/:ref_name/raw/*artifact_path

Why are we doing this?

When fetching artifact using ArtifactsController#raw method they are served with their "real" MIME type in the Content-Type headers. This allows an attacker to host a malicious JavaScript payload as an artifact and bypass our CSP.

Testing locally

  1. Create a job which generate an artifact (in this example I've used a javascript file)
  2. Here a snippet of the artifact I've created in my .gitlatb-ci.yml
test-workhorse-header:
  script:
    - echo "alert('hello!');" > hello.js
  artifacts:
    paths:
      - hello.js
  1. Verify the headers of the response with curl
$ curl --head -i 127.0.0.1:3000/root/<PROJECT_ID>/-/jobs/<JOB_ID>/artifacts/raw/hello.js

Screenshots

Before this MR

Content-Type application/javascript
➜  gitlab git:(master) ✗ curl --head -i http://127.0.0.1:3000/root/test-workhorse-header/-/jobs/769/artifacts/raw/hello.js
HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Disposition: attachment; filename="hello.js"
Content-Length: 17
Content-Security-Policy: base-uri 'self'; child-src https://www.google.com/recaptcha/ https://www.recaptcha.net/ https://content.googleapis.com https://content-compute.googleapis.com https://content-cloudbilling.googleapis.com https://content-cloudresourcemanager.googleapis.com https://www.googletagmanager.com/ns.html http://127.0.0.1:3000/rails/letter_opener/ http://127.0.0.1:3000/admin/ http://127.0.0.1:3000/assets/ http://127.0.0.1:3000/-/speedscope/index.html http://127.0.0.1:3000/-/sandbox/mermaid http://127.0.0.1:3000/assets/ blob: data:; connect-src 'self' http://127.0.0.1:3808 ws://127.0.0.1:3808 ws://127.0.0.1:3000; default-src 'self'; font-src 'self'; form-action 'self' https: http:; frame-ancestors 'self'; frame-src https://www.google.com/recaptcha/ https://www.recaptcha.net/ https://content.googleapis.com https://content-compute.googleapis.com https://content-cloudbilling.googleapis.com https://content-cloudresourcemanager.googleapis.com https://www.googletagmanager.com/ns.html http://127.0.0.1:3000/rails/letter_opener/ http://127.0.0.1:3000/admin/ http://127.0.0.1:3000/assets/ http://127.0.0.1:3000/-/speedscope/index.html http://127.0.0.1:3000/-/sandbox/mermaid; img-src 'self' data: blob: http: https:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src 'strict-dynamic' 'self' 'unsafe-inline' 'unsafe-eval' https://www.google.com/recaptcha/ https://www.recaptcha.net https://apis.google.com 'nonce-V95XI2Lo/57qhXOoL9VXLg=='; style-src 'self' 'unsafe-inline'; worker-src http://127.0.0.1:3000/assets/ blob: data:
- Content-Type: application/javascript
Permissions-Policy: interest-cohort=()
Pragma: no-cache
Referrer-Policy: strict-origin-when-cross-origin
Set-Cookie: perf_bar_enabled=true; path=/
X-Accel-Buffering: no
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Frame-Options: SAMEORIGIN
X-Permitted-Cross-Domain-Policies: none
X-Request-Id: 01FY9FF1M0VS8BD3Q6T5PYW8W2
X-Runtime: 0.388220
X-Ua-Compatible: IE=edge
X-Xss-Protection: 1; mode=block
Date: Wed, 16 Mar 2022 13:42:50 GMT

After this MR

Content-Type text/plain
➜  gitlab git:(master) ✗ curl --head -i http://127.0.0.1:3000/root/test-workhorse-header/-/jobs/769/artifacts/raw/hello.js
HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Disposition: attachment; filename="hello.js"
Content-Length: 17
Content-Security-Policy: base-uri 'self'; child-src https://www.google.com/recaptcha/ https://www.recaptcha.net/ https://content.googleapis.com https://content-compute.googleapis.com https://content-cloudbilling.googleapis.com https://content-cloudresourcemanager.googleapis.com https://www.googletagmanager.com/ns.html http://127.0.0.1:3000/rails/letter_opener/ http://127.0.0.1:3000/admin/ http://127.0.0.1:3000/assets/ http://127.0.0.1:3000/-/speedscope/index.html http://127.0.0.1:3000/-/sandbox/mermaid http://127.0.0.1:3000/assets/ blob: data:; connect-src 'self' http://127.0.0.1:3808 ws://127.0.0.1:3808 ws://127.0.0.1:3000; default-src 'self'; font-src 'self'; form-action 'self' https: http:; frame-ancestors 'self'; frame-src https://www.google.com/recaptcha/ https://www.recaptcha.net/ https://content.googleapis.com https://content-compute.googleapis.com https://content-cloudbilling.googleapis.com https://content-cloudresourcemanager.googleapis.com https://www.googletagmanager.com/ns.html http://127.0.0.1:3000/rails/letter_opener/ http://127.0.0.1:3000/admin/ http://127.0.0.1:3000/assets/ http://127.0.0.1:3000/-/speedscope/index.html http://127.0.0.1:3000/-/sandbox/mermaid; img-src 'self' data: blob: http: https:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src 'strict-dynamic' 'self' 'unsafe-inline' 'unsafe-eval' https://www.google.com/recaptcha/ https://www.recaptcha.net https://apis.google.com 'nonce-jbH65kov3LsrnoNS0blojQ=='; style-src 'self' 'unsafe-inline'; worker-src http://127.0.0.1:3000/assets/ blob: data:
+ Content-Type: text/plain; charset=utf-8
Permissions-Policy: interest-cohort=()
Pragma: no-cache
Referrer-Policy: strict-origin-when-cross-origin
Server: thin
Set-Cookie: perf_bar_enabled=true; path=/
X-Accel-Buffering: no
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Frame-Options: SAMEORIGIN
X-Permitted-Cross-Domain-Policies: none
X-Request-Id: 01FY9FJ7SVW03Q1GVZ7NGBSQ5W
X-Runtime: 6.694900
X-Ua-Compatible: IE=edge
X-Xss-Protection: 1; mode=block
Date: Wed, 16 Mar 2022 13:44:41 GMT

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Merge request reports