Skip to content

Add ability to easily sanitize attributes

What does this MR do?

introduces a model concern that makes it straightforward to sanitize fields by stripping out html and also validates that these fields do not already contain escaped html entities. validation is used to prevent issues like Stored XSS in milestone tooltips which leveraged entity escaping to introduce an xss vulnerability.

the intention is to help prevent xss attacks in the event of a by-pass in the frontend sanitizer due to a configuration issue or a vulnerability in the sanitizer. this approach is commonly referred to as defense-in-depth. this approach was validated with appsec.

Notes

i would prefer not to have added validations but ruby html sanitization libraries typically use nokogiri which always does entity escaping and there's no obvious way around this. you can read more about this decision in earlier discussion on this merge request.

What does this MR not do?

this merge request is not a silver bullet. it is a redundancy measure.

When should this be used?

when you know that your upfront data should never include any html.

Example

Definition

class SomeModel
  include ActiveModel::Model
  include ActiveModel::Attributes
  include ActiveModel::Validations
  include ActiveModel::Validations::Callbacks
  include Sanitizable

  attribute :id, :string
  attribute :name, :string
  attribute :description, :string
  attribute :label, :string
  attribute :html_body, :string

  sanitizes! :name, :description, :label
end

Output

Setup
[1] pry(main)> instance = SomeModel.new(
  id: 1,
  name: 'hello<script>alert(1)</script>, world',
  description: 'hello&world',
  label: 'hello&lt;script&gt;alert(1)&lt;/script&gt;, world',
  html_body: '<div>hello, world</div>'
)
Validation
[1] pry(main)> instance.valid?
=> false
[2] pry(main)> instance.errors.full_messages
=> ["Label cannot contain escaped HTML entities"]
Sanitization
[3] pry(main)> puts instance.attributes
=> {"id"=>"1", "name"=>"hello, world", "description"=>"hello&world", "label"=>"hello&lt;script&gt;alert(1)&lt;/script&gt;, world", "html_body"=>"<div>hello, world</div>"}

please note that sanitization happens in a before_validation callback.

Relates Issue(s)

https://gitlab.com/gitlab-org/gitlab/-/issues/334653

Follow-up Merge requests

Use new Sanitizable concern in other models

Does this MR meet the acceptance criteria?

Conformity

Availability and Testing

Security

Does this MR contain changes to processing or storing of credentials or tokens, authorization and authentication methods or other items described in the security review guidelines? If not, then delete this Security section.

  • Label as security and @ mention @gitlab-com/gl-security/appsec
  • The MR includes necessary changes to maintain consistency between UI, API, email, or other methods
  • Security reports checked/validated by a reviewer from the AppSec team
Edited by Philip Cunningham

Merge request reports