Skip to content
GitLab
Next
    • GitLab: the DevOps platform
    • Explore GitLab
    • Install GitLab
    • How GitLab compares
    • Get started
    • GitLab docs
    • GitLab Learn
  • Pricing
  • Talk to an expert
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
    Projects Groups Topics Snippets
  • Register
  • Sign in
  • GitLab GitLab
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributor statistics
    • Graph
    • Compare revisions
    • Locked files
  • Issues 54.9k
    • Issues 54.9k
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
    • Requirements
  • Merge requests 1.5k
    • Merge requests 1.5k
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Artifacts
    • Schedules
    • Test cases
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages and registries
    • Packages and registries
    • Package Registry
    • Container Registry
    • Terraform modules
    • Model experiments
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Code review
    • Insights
    • Issue
    • Repository
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • GitLab.orgGitLab.org
  • GitLabGitLab
  • Issues
  • #377473
Closed
Open
Issue created Oct 10, 2022 by Cameron Swords@cam_swordsDeveloper

Restrict sending custom request headers to allowed hosts

Problem

DAST sends user configured custom request headers with every request, regardless of the host. This can cause the following issues:

  • A request that was previously a simple CORS request becomes a preflighted request
  • Scans are slower due to the extra preflighted HTTP request (one per external resource request)
  • If the external host rejects the preflight request due to the additional header, it's likely the user's scan will fail (missing JavaScript, CSS, etc)
  • If the external host accepts the preflight request despite the additional header, the the request header is sent to the external host. This can be a security issue, depending on what was configured in the request headers.

This only affects requests made by a browser.

Proposal

Limit custom request headers to only be sent on DAST_BROWSER_ALLOWED_HOSTS. This is a breaking change.

This applies to the CI/CD variables DAST_REQUEST_HEADERS_BASE64, DAST_REQUEST_HEADER and DAST_REQUEST_HEADERS.

Proof that tokens may be leaked

The following redacted log was taken from a customer scan:

2022-10-06T05:30:16.000 TRC CHROM event received  {"method":"Network.requestWillBeSent","params":
{"requestId":"240.6","loaderId":"4E1105698FC8652047FB127FDC470C3B","documentURL":"<redacted>","request":
{"url":"https://use.fontawesome.com/releases/v6.2.0/css/all.css","method":"GET","headers":{"Authorization":"Bearer <secret-token>",...

Reference

From customer issue, see internal Slack thread.

Example

A user has a target website, that loads bootstrap JavaScript from an external CDN. A simple CORS request is made, to get the JavaScript. This is a GET HTTP request, where the response is status 200, the resource body contains the JavaScript and there is a Access-Control-Allow-Origin response header.

Page source Network requests
<html>
<body>
Hello world!

<script>
  let host = "maxcdn.bootstrapcdn.com"
  let url = "https://" + host + "/bootstrap/3.3.7/js/bootstrap.min.js"
  fetch(url)
</script>
</body>
</html>

Suppose the user adds a custom authorization token header, DAST_REQUEST_HEADERS: "Authorization: Bearer secret.token". The following network requests show that an extra request is made, a preflight CORS request. In this case, maxcdn.bootstrapcdn.com rejects the preflight request, therefore the JavaScript is unable to load.

Page source Network requests
<html>
<body>
Hello world!

<script>
  let host = "maxcdn.bootstrapcdn.com"
  let url = "https://" + host + "/bootstrap/3.3.7/js/bootstrap.min.js"
  fetch(url, {headers: {"Authorization": "Bearer secret.token"}})
</script>
</body>
</html>

Implementation plan

  • Remove the call to Network.setExtraHTTPHeaders (DevTools), as this indiscriminately adds headers to every request made by the current browser tab (https://gitlab.com/gitlab-org/security-products/analyzers/browserker/-/merge_requests/881/)
  • Store the custom headers and allowed hosts as new fields on the browser.Tab (see Tab.Init/setCustomHeaders) (https://gitlab.com/gitlab-org/security-products/analyzers/browserker/-/merge_requests/881/)
  • The DevTools event Fetch.requestPaused (DevTools) is used to intercept all requests and responses. When a request is continued, add the custom headers to ContinueRequestWithParams if the request host is an allowed host. The headers/allowed hosts can be retrieved from the tab. (part 1: https://gitlab.com/gitlab-org/security-products/analyzers/browserker/-/merge_requests/881/, part 2: https://gitlab.com/gitlab-org/security-products/analyzers/browserker/-/merge_requests/885)
  • Using an integration test, verify that extra headers are sent, but only to allowed hosts
    • TestCookiesAreRecordedWhenNavigationIsExecuted is a good example of such a test. More than one HTTP server could be created, so that there is more than one host. The second server could load a CSS file from the first server, emulating the problem.
Edited Oct 13, 2022 by Philip Cunningham
Assignee
Assign to
Time tracking