diff --git a/lib/content_security_policy/builder.rb b/lib/content_security_policy/builder.rb index e23f55111e2..14478cadf6f 100644 --- a/lib/content_security_policy/builder.rb +++ b/lib/content_security_policy/builder.rb @@ -43,6 +43,10 @@ class ContentSecurityPolicy @directives.each do |directive, sources| if sources.is_a?(Array) + if sources.include?("'unsafe-inline'") + # Sending nonce- or sha###- values will disable unsafe-inline, so skip them + sources = sources.reject { |s| s.start_with?("'nonce-", "'sha") } + end policy.public_send(directive, *sources) else policy.public_send(directive, sources) diff --git a/spec/lib/content_security_policy/builder_spec.rb b/spec/lib/content_security_policy/builder_spec.rb index ec58256d2ab..63398eaec05 100644 --- a/spec/lib/content_security_policy/builder_spec.rb +++ b/spec/lib/content_security_policy/builder_spec.rb @@ -35,6 +35,25 @@ RSpec.describe ContentSecurityPolicy::Builder do expect(builder.build).to eq(previous) end + + it "omits nonce when unsafe-inline enabled" do + builder << { script_src: %w['unsafe-inline' 'nonce-abcde'] } + + expect(builder.build).not_to include("nonce-abcde") + end + + it "omits sha when unsafe-inline enabled" do + builder << { script_src: %w['unsafe-inline' 'sha256-abcde'] } + + expect(builder.build).not_to include("sha256-abcde") + end + + it "keeps sha and nonce when unsafe-inline is not specified" do + builder << { script_src: %w['nonce-abcde' 'sha256-abcde'] } + + expect(builder.build).to include("nonce-abcde") + expect(builder.build).to include("sha256-abcde") + end end def parse(csp_string)