ruby.rails.security.audit.xss.avoid-raw.avoid-raw

Author
6,305
Download Count*
License
'raw()' bypasses HTML escaping. If external data can reach here, this exposes your application to cross-site scripting (XSS) attacks. If you must do this, construct individual strings and mark them as safe for HTML rendering with html_safe()
.
Run Locally
Run in CI
Defintion
rules:
- id: avoid-raw
metadata:
source-rule-url: https://github.com/presidentbeef/brakeman/blob/main/lib/brakeman/checks/check_cross_site_scripting.rb
owasp:
- A07:2017 - Cross-Site Scripting (XSS)
- A03:2021 - Injection
cwe:
- "CWE-79: Improper Neutralization of Input During Web Page Generation
('Cross-site Scripting')"
references:
- https://api.rubyonrails.org/classes/ActionView/Helpers/OutputSafetyHelper.html#method-i-raw
- https://www.netsparker.com/blog/web-security/preventing-xss-ruby-on-rails-web-applications/
category: security
technology:
- rails
cwe2022-top25: true
cwe2021-top25: true
subcategory:
- audit
likelihood: LOW
impact: MEDIUM
confidence: LOW
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
message: "'raw()' bypasses HTML escaping. If external data can reach here, this
exposes your application to cross-site scripting (XSS) attacks. If you
must do this, construct individual strings and mark them as safe for HTML
rendering with `html_safe()`."
languages:
- ruby
severity: WARNING
pattern: raw(...)
Examples
avoid-raw.rb
# cf. https://github.com/rails/rails/blob/62d089a4ad0170320b851addf76f7f48a49d68d8/actionview/test/template/output_safety_helper_test.rb
# frozen_string_literal: true
require "abstract_unit"
class OutputSafetyHelperTest < ActionView::TestCase
tests ActionView::Helpers::OutputSafetyHelper
def setup
@string = "hello"
end
test "raw returns the safe string" do
# ruleid: avoid-raw
result = raw(@string)
assert_equal @string, result
assert_predicate result, :html_safe?
end
test "raw handles nil values correctly" do
# ruleid: avoid-raw
assert_equal "", raw(nil)
end
test "safe_join should html_escape any items, including the separator, if they are not html_safe" do
# ruleid: avoid-raw
joined = safe_join([raw("<p>foo</p>"), "<p>bar</p>"], "<br />")
assert_equal "<p>foo</p><br /><p>bar</p>", joined
# ruleid: avoid-raw
joined = safe_join([raw("<p>foo</p>"), raw("<p>bar</p>")], raw("<br />"))
assert_equal "<p>foo</p><br /><p>bar</p>", joined
end
test "safe_join should work recursively similarly to Array.join" do
joined = safe_join(["a", ["b", "c"]], ":")
assert_equal "a:b:c", joined
joined = safe_join(['"a"', ["<b>", "<c>"]], " <br/> ")
assert_equal ""a" <br/> <b> <br/> <c>", joined
end
test "safe_join should return the safe string separated by $, when second argument is not passed" do
default_delimeter = $,
begin
$, = nil
joined = safe_join(["a", "b"])
assert_equal "ab", joined
silence_warnings do
$, = "|"
end
joined = safe_join(["a", "b"])
assert_equal "a|b", joined
ensure
$, = default_delimeter
end
end
end
Short Link: https://sg.run/nqJG