Fix gl-show-field-errors Content-Security-Policy bypass
Summary
The JavaScript handling the CSS class gl-show-field-errors
(https://gitlab.com/gitlab-org/gitlab/-/blob/d3969b315beaa52a8afb773a466db4b0f6f3c65e/app/assets/javascripts/gl_field_error.js) creates a Content Security Policy bypass as demonstrated in #409346 (closed)
If someone can inject arbitrary HTML due to an XSS vulnerability they can leverage the GlFieldError
to execute arbitrary code that isn't subject to our Content Security Policy restrictions.
Steps to reproduce
See Stored-XSS with CSP-bypass in Merge requests (#409346 - closed)
The payload used for the XSS was XSS<i/class=hidden><form/class=gl-show-field-errors><input/title='<script>alert(document.domain)</script>'>
which created a form with a validation and our own GlFieldError
code took that title
attribute and injected it into the DOM bypassing the Content Security Policy which is supposed to mitigate XSS.
Example Project
What is the current bug behavior?
GlFieldError
will render anything
What is the expected correct behavior?
GlFieldError
shouldn't render dangerous scripts
Relevant logs and/or screenshots
Output of checks
This bug happens on GitLab.com
Results of GitLab environment info
Expand for output related to GitLab environment info
(For installations with omnibus-gitlab package run and paste the output of: `sudo gitlab-rake gitlab:env:info`) (For installations from source run and paste the output of: `sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`)
Results of GitLab application Check
Expand for output related to the GitLab application check
(For installations with omnibus-gitlab package run and paste the output of:
sudo gitlab-rake gitlab:check SANITIZE=true
)(For installations from source run and paste the output of:
sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true
)(we will only investigate if the tests are passing)
Possible fixes
If we do expect the error message on this line to contain HTML under normal conditions
this.fieldErrorElement = $(`<p class='${errorMessageClass} hidden'>${this.errorMessage}</p>`);
then we should sanitize it with DOMPurify. Otherwise we should either strip HTML tags or throw an error when it contains HTML.