Files
discourse/spec/lib/content_security_policy/builder_spec.rb
Kelv b751742573 FIX: invalid CSP directive sources should allow site to boot with valid CSP directives (#31256)
[Security
patch](5558e72f22)
(for this [CVE](https://nvd.nist.gov/vuln/detail/CVE-2024-54133)) from
rails actionpack was backported from [Rails
8.0.0.1](https://github.com/rails/rails/blob/v8.0.1/actionpack/CHANGELOG.md#rails-8001-december-10-2024)
to previous stable versions including `7-1-stable` / `7-2-stable`.

Any previous version of Discourse upgrading to v3.4.0.beta3 and above
would have observed their sites crashing if they had invalid sources in
their CSP directive extensions.

This fix removes such invalid sources during our build of the CSP, and
logs these at a warning level so devs are able to find out why their CSP
sources were filtered out of the extendable directives.
2025-02-10 20:38:36 +08:00

57 lines
1.6 KiB
Ruby

# frozen_string_literal: true
RSpec.describe ContentSecurityPolicy::Builder do
let(:builder) { described_class.new(base_url: Discourse.base_url) }
describe "#<<" do
it "normalizes directive name" do
builder << {
:script_src => ["'symbol_underscore'"],
:"script-src" => ["'symbol_dash'"],
"script_src" => ["'string_underscore'"],
"script-src" => ["'string_dash'"],
}
script_srcs = parse(builder.build)["script-src"]
expect(script_srcs).to include(
*%w['symbol_underscore' 'symbol_dash' 'string_underscore' 'symbol_underscore'],
)
end
it "rejects invalid directives and ones that are not allowed to be extended" do
builder << { invalid_src: ["invalid"] }
expect(builder.build).to_not include("invalid")
end
it "skips invalid sources with whitespace or semicolons" do
invalid_sources = ["invalid source;", "'unsafe-eval' https://invalid.example.com'"]
builder << { script_src: invalid_sources }
script_srcs = parse(builder.build)["script-src"]
invalid_sources.each { |invalid_source| expect(script_srcs).not_to include(invalid_source) }
end
it "no-ops on invalid values" do
previous = builder.build
builder << nil
builder << 123
builder << "string"
builder << []
builder << {}
expect(builder.build).to eq(previous)
end
end
def parse(csp_string)
csp_string
.split(";")
.map do |policy|
directive, *sources = policy.split
[directive, sources]
end
.to_h
end
end