Bug 1299483 - CSP: Implement 'strict-dynamic', enforcement changes. r=dveditz,freddyb
authorChristoph Kerschbaumer <ckerschb@christophkerschbaumer.com>
Tue, 08 Nov 2016 12:55:23 +0100
changeset 351747 22f5124ac4b6ba1e080081ac659871d178a9c929
parent 351746 fe3fe09d24c8619d7b4a71aa6c5fccdb05f98636
child 351748 908b79c3788827e44af80f75f99396ec7f626ecb
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdveditz, freddyb
bugs1299483
milestone52.0a1
Bug 1299483 - CSP: Implement 'strict-dynamic', enforcement changes. r=dveditz,freddyb
dom/base/nsDocument.cpp
dom/base/nsScriptLoader.cpp
dom/events/EventListenerManager.cpp
dom/interfaces/security/nsIContentSecurityPolicy.idl
dom/jsurl/nsJSProtocolHandler.cpp
dom/security/nsCSPContext.cpp
dom/security/nsCSPContext.h
dom/security/nsCSPUtils.cpp
dom/security/nsCSPUtils.h
dom/security/test/unit/test_csp_reports.js
layout/style/nsStyleUtil.cpp
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -12263,16 +12263,17 @@ nsIDocument::InlineScriptAllowedByCSP()
 {
   nsCOMPtr<nsIContentSecurityPolicy> csp;
   nsresult rv = NodePrincipal()->GetCsp(getter_AddRefs(csp));
   NS_ENSURE_SUCCESS(rv, true);
   bool allowsInlineScript = true;
   if (csp) {
     nsresult rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
                                        EmptyString(), // aNonce
+                                       false,         // parserCreated
                                        EmptyString(), // FIXME get script sample (bug 1314567)
                                        0,             // aLineNumber
                                        &allowsInlineScript);
     NS_ENSURE_SUCCESS(rv, true);
   }
   return allowsInlineScript;
 }
 
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -1377,24 +1377,25 @@ CSPAllowsInlineScript(nsIScriptElement *
     // no CSP --> allow
     return true;
   }
 
   // query the nonce
   nsCOMPtr<nsIContent> scriptContent = do_QueryInterface(aElement);
   nsAutoString nonce;
   scriptContent->GetAttr(kNameSpaceID_None, nsGkAtoms::nonce, nonce);
+  bool parserCreated = aElement->GetParserCreated() != mozilla::dom::NOT_FROM_PARSER;
 
   // query the scripttext
   nsAutoString scriptText;
   aElement->GetScriptText(scriptText);
 
   bool allowInlineScript = false;
   rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
-                            nonce, scriptText,
+                            nonce, parserCreated, scriptText,
                             aElement->GetScriptLineNumber(),
                             &allowInlineScript);
   return allowInlineScript;
 }
 
 nsScriptLoadRequest*
 nsScriptLoader::CreateLoadRequest(nsScriptKind aKind,
                                   nsIScriptElement* aElement,
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -867,16 +867,17 @@ EventListenerManager::SetEventHandler(ns
       scriptSample.Assign(attr);
       scriptSample.AppendLiteral(" attribute on ");
       scriptSample.Append(tagName);
       scriptSample.AppendLiteral(" element");
 
       bool allowsInlineScript = true;
       rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
                                 EmptyString(), // aNonce
+                                false, // aParserCreated
                                 scriptSample,
                                 0,             // aLineNumber
                                 &allowsInlineScript);
       NS_ENSURE_SUCCESS(rv, rv);
 
       // return early if CSP wants us to block inline scripts
       if (!allowsInlineScript) {
         return NS_OK;
--- a/dom/interfaces/security/nsIContentSecurityPolicy.idl
+++ b/dom/interfaces/security/nsIContentSecurityPolicy.idl
@@ -126,26 +126,28 @@ interface nsIContentSecurityPolicy : nsI
   void appendPolicy(in AString policyString,
                     in boolean reportOnly,
                     in boolean deliveredViaMetaTag);
 
   /*
    * Whether this policy allows inline script or style.
    * @param aContentPolicyType Either TYPE_SCRIPT or TYPE_STYLESHEET
    * @param aNonce The nonce string to check against the policy
+   * @param aParserCreated If the script element was created by the HTML Parser
    * @param aContent  The content of the inline resource to hash
    *        (and compare to the hashes listed in the policy)
    * @param aLineNumber The line number of the inline resource
    *        (used for reporting)
    * @return
    *     Whether or not the effects of the inline style should be allowed
    *     (block the rules if false).
    */
   boolean getAllowsInline(in nsContentPolicyType aContentPolicyType,
                           in AString aNonce,
+                          in boolean aParserCreated,
                           in AString aContent,
                           in unsigned long aLineNumber);
 
   /**
    * whether this policy allows eval and eval-like functions
    * such as setTimeout("code string", time).
    * @param shouldReportViolations
    *     Whether or not the use of eval should be reported.
--- a/dom/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/jsurl/nsJSProtocolHandler.cpp
@@ -178,16 +178,17 @@ nsresult nsJSThunk::EvaluateScript(nsICh
     // allowed.
     nsCOMPtr<nsIContentSecurityPolicy> csp;
     rv = principal->GetCsp(getter_AddRefs(csp));
     NS_ENSURE_SUCCESS(rv, rv);
     if (csp) {
         bool allowsInlineScript = true;
         rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
                                   EmptyString(), // aNonce
+                                  false,         // aParserCreated
                                   EmptyString(), // aContent
                                   0,             // aLineNumber
                                   &allowsInlineScript);
 
         //return early if inline scripts are not allowed
         if (!allowsInlineScript) {
           return NS_ERROR_DOM_RETVAL_UNDEFINED;
         }
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -38,16 +38,17 @@
 #include "nsScriptSecurityManager.h"
 #include "nsStringStream.h"
 #include "mozilla/Logging.h"
 #include "mozilla/dom/CSPReportBinding.h"
 #include "mozilla/dom/CSPDictionariesBinding.h"
 #include "mozilla/net/ReferrerPolicy.h"
 #include "nsINetworkInterceptController.h"
 #include "nsSandboxFlags.h"
+#include "nsIScriptElement.h"
 
 using namespace mozilla;
 
 static LogModule*
 GetCspContextLog()
 {
   static LazyLogModule gCspContextPRLog("CSPContext");
   return gCspContextPRLog;
@@ -148,37 +149,44 @@ nsCSPContext::ShouldLoad(nsContentPolicy
   // If the content type doesn't map to a CSP directive, there's nothing for
   // CSP to do.
   CSPDirective dir = CSP_ContentTypeToDirective(aContentType);
   if (dir == nsIContentSecurityPolicy::NO_DIRECTIVE) {
     return NS_OK;
   }
 
   nsAutoString nonce;
+  bool parserCreated = false;
   if (!isPreload) {
     nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(aRequestContext);
     if (htmlElement) {
       rv = htmlElement->GetAttribute(NS_LITERAL_STRING("nonce"), nonce);
       NS_ENSURE_SUCCESS(rv, rv);
     }
+
+    nsCOMPtr<nsIScriptElement> script = do_QueryInterface(aRequestContext);
+    if (script && script->GetParserCreated() != mozilla::dom::NOT_FROM_PARSER) {
+      parserCreated = true;
+    }
   }
 
   // aExtra is only non-null if the channel got redirected.
   bool wasRedirected = (aExtra != nullptr);
   nsCOMPtr<nsIURI> originalURI = do_QueryInterface(aExtra);
 
   bool permitted = permitsInternal(dir,
                                    aContentLocation,
                                    originalURI,
                                    nonce,
                                    wasRedirected,
                                    isPreload,
                                    false,     // allow fallback to default-src
                                    true,      // send violation reports
-                                   true);     // send blocked URI in violation reports
+                                   true,     // send blocked URI in violation reports
+                                   parserCreated);
 
   *outDecision = permitted ? nsIContentPolicy::ACCEPT
                            : nsIContentPolicy::REJECT_SERVER;
 
   // Done looping, cache any relevant result
   if (cacheKey.Length() > 0 && !isPreload) {
     mShouldLoadCache.Put(cacheKey, *outDecision);
   }
@@ -196,17 +204,18 @@ bool
 nsCSPContext::permitsInternal(CSPDirective aDir,
                               nsIURI* aContentLocation,
                               nsIURI* aOriginalURI,
                               const nsAString& aNonce,
                               bool aWasRedirected,
                               bool aIsPreload,
                               bool aSpecific,
                               bool aSendViolationReports,
-                              bool aSendContentLocationInViolationReports)
+                              bool aSendContentLocationInViolationReports,
+                              bool aParserCreated)
 {
   bool permits = true;
 
   nsAutoString violatedDirective;
   for (uint32_t p = 0; p < mPolicies.Length(); p++) {
 
     // According to the W3C CSP spec, frame-ancestors checks are ignored for
     // report-only policies (when "monitoring").
@@ -215,16 +224,17 @@ nsCSPContext::permitsInternal(CSPDirecti
       continue;
     }
 
     if (!mPolicies[p]->permits(aDir,
                                aContentLocation,
                                aNonce,
                                aWasRedirected,
                                aSpecific,
+                               aParserCreated,
                                violatedDirective)) {
       // If the policy is violated and not report-only, reject the load and
       // report to the console
       if (!mPolicies[p]->getReportOnlyFlag()) {
         CSPCONTEXTLOG(("nsCSPContext::permitsInternal, false"));
         permits = false;
       }
 
@@ -399,17 +409,19 @@ NS_IMETHODIMP
 nsCSPContext::GetAllowsEval(bool* outShouldReportViolation,
                             bool* outAllowsEval)
 {
   *outShouldReportViolation = false;
   *outAllowsEval = true;
 
   for (uint32_t i = 0; i < mPolicies.Length(); i++) {
     if (!mPolicies[i]->allows(nsIContentPolicy::TYPE_SCRIPT,
-                              CSP_UNSAFE_EVAL, EmptyString())) {
+                              CSP_UNSAFE_EVAL,
+                              EmptyString(),
+                              false)) {
       // policy is violated: must report the violation and allow the inline
       // script if the policy is report-only.
       *outShouldReportViolation = true;
       if (!mPolicies[i]->getReportOnlyFlag()) {
         *outAllowsEval = false;
       }
     }
   }
@@ -466,16 +478,17 @@ nsCSPContext::reportInlineViolation(nsCo
                        NS_ConvertUTF8toUTF16(sourceFile),  // aSourceFile
                        codeSample,                         // aScriptSample
                        aLineNumber);                       // aLineNum
 }
 
 NS_IMETHODIMP
 nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType,
                               const nsAString& aNonce,
+                              bool aParserCreated,
                               const nsAString& aContent,
                               uint32_t aLineNumber,
                               bool* outAllowsInline)
 {
   *outAllowsInline = true;
 
   MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType),
              "We should only see external content policy types here.");
@@ -484,19 +497,19 @@ nsCSPContext::GetAllowsInline(nsContentP
       aContentType != nsIContentPolicy::TYPE_STYLESHEET) {
     MOZ_ASSERT(false, "can only allow inline for script or style");
     return NS_OK;
   }
 
   // always iterate all policies, otherwise we might not send out all reports
   for (uint32_t i = 0; i < mPolicies.Length(); i++) {
     bool allowed =
-      mPolicies[i]->allows(aContentType, CSP_UNSAFE_INLINE, EmptyString()) ||
-      mPolicies[i]->allows(aContentType, CSP_NONCE, aNonce) ||
-      mPolicies[i]->allows(aContentType, CSP_HASH, aContent);
+      mPolicies[i]->allows(aContentType, CSP_UNSAFE_INLINE, EmptyString(), aParserCreated) ||
+      mPolicies[i]->allows(aContentType, CSP_NONCE, aNonce, aParserCreated) ||
+      mPolicies[i]->allows(aContentType, CSP_HASH, aContent, aParserCreated);
 
     if (!allowed) {
       // policy is violoated: deny the load unless policy is report only and
       // report the violation.
       if (!mPolicies[i]->getReportOnlyFlag()) {
         *outAllowsInline = false;
       }
       nsAutoString violatedDirective;
@@ -530,23 +543,27 @@ nsCSPContext::GetAllowsInline(nsContentP
  * @param violationType: the VIOLATION_TYPE_* constant (partial symbol)
  *                 such as INLINE_SCRIPT
  * @param contentPolicyType: a constant from nsIContentPolicy such as TYPE_STYLESHEET
  * @param nonceOrHash: for NONCE and HASH violations, it's the nonce or content
  *               string. For other violations, it is an empty string.
  * @param keyword: the keyword corresponding to violation (UNSAFE_INLINE for most)
  * @param observerTopic: the observer topic string to send with the CSP
  *                 observer notifications.
+ *
+ * Please note that inline violations for scripts are reported within
+ * GetAllowsInline() and do not call this macro, hence we can pass 'false'
+ * as the argument _aParserCreated_ to allows().
  */
 #define CASE_CHECK_AND_REPORT(violationType, contentPolicyType, nonceOrHash,   \
                               keyword, observerTopic)                          \
   case nsIContentSecurityPolicy::VIOLATION_TYPE_ ## violationType :            \
     PR_BEGIN_MACRO                                                             \
     if (!mPolicies[p]->allows(nsIContentPolicy::TYPE_ ## contentPolicyType,    \
-                              keyword, nonceOrHash))                           \
+                              keyword, nonceOrHash, false))                    \
     {                                                                          \
       nsAutoString violatedDirective;                                          \
       mPolicies[p]->getDirectiveStringForContentType(                          \
                         nsIContentPolicy::TYPE_ ## contentPolicyType,          \
                         violatedDirective);                                    \
       this->AsyncReportViolation(selfISupports, nullptr, violatedDirective, p, \
                                  NS_LITERAL_STRING(observerTopic),             \
                                  aSourceFile, aScriptSample, aLineNum);        \
@@ -1263,17 +1280,18 @@ nsCSPContext::PermitsAncestry(nsIDocShel
     bool permits = permitsInternal(nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE,
                                    ancestorsArray[a],
                                    nullptr, // no redirect here.
                                    EmptyString(), // no nonce
                                    false,   // no redirect here.
                                    false,   // not a preload.
                                    true,    // specific, do not use default-src
                                    true,    // send violation reports
-                                   okToSendAncestor);
+                                   okToSendAncestor,
+                                   false);  // not parser created
     if (!permits) {
       *outPermitsAncestry = false;
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -1290,17 +1308,18 @@ nsCSPContext::Permits(nsIURI* aURI,
   *outPermits = permitsInternal(aDir,
                                 aURI,
                                 nullptr,  // no original (pre-redirect) URI
                                 EmptyString(),  // no nonce
                                 false,    // not redirected.
                                 false,    // not a preload.
                                 aSpecific,
                                 true,     // send violation reports
-                                true);    // send blocked URI in violation reports
+                                true,     // send blocked URI in violation reports
+                                false);   // not parser created
 
   if (CSPCONTEXTLOGENABLED()) {
       CSPCONTEXTLOG(("nsCSPContext::Permits, aUri: %s, aDir: %d, isAllowed: %s",
                      aURI->GetSpecOrDefault().get(), aDir,
                      *outPermits ? "allow" : "deny"));
   }
 
   return NS_OK;
--- a/dom/security/nsCSPContext.h
+++ b/dom/security/nsCSPContext.h
@@ -89,17 +89,18 @@ class nsCSPContext : public nsIContentSe
     bool permitsInternal(CSPDirective aDir,
                          nsIURI* aContentLocation,
                          nsIURI* aOriginalURI,
                          const nsAString& aNonce,
                          bool aWasRedirected,
                          bool aIsPreload,
                          bool aSpecific,
                          bool aSendViolationReports,
-                         bool aSendContentLocationInViolationReports);
+                         bool aSendContentLocationInViolationReports,
+                         bool aParserCreated);
 
     // helper to report inline script/style violations
     void reportInlineViolation(nsContentPolicyType aContentType,
                                const nsAString& aNonce,
                                const nsAString& aContent,
                                const nsAString& aViolatedDirective,
                                uint32_t aViolatedPolicyIndex,
                                uint32_t aLineNumber);
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -419,42 +419,44 @@ CSP_AppendCSPFromHeader(nsIContentSecuri
     }
   }
   return NS_OK;
 }
 
 /* ===== nsCSPSrc ============================ */
 
 nsCSPBaseSrc::nsCSPBaseSrc()
+  : mInvalidated(false)
 {
 }
 
 nsCSPBaseSrc::~nsCSPBaseSrc()
 {
 }
 
 // ::permits is only called for external load requests, therefore:
 // nsCSPKeywordSrc and nsCSPHashSource fall back to this base class
 // implementation which will never allow the load.
 bool
 nsCSPBaseSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
-                      bool aReportOnly, bool aUpgradeInsecure) const
+                      bool aReportOnly, bool aUpgradeInsecure, bool aParserCreated) const
 {
   if (CSPUTILSLOGENABLED()) {
     CSPUTILSLOG(("nsCSPBaseSrc::permits, aUri: %s",
                  aUri->GetSpecOrDefault().get()));
   }
   return false;
 }
 
 // ::allows is only called for inlined loads, therefore:
 // nsCSPSchemeSrc, nsCSPHostSrc fall back
 // to this base class implementation which will never allow the load.
 bool
-nsCSPBaseSrc::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const
+nsCSPBaseSrc::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
+                     bool aParserCreated) const
 {
   CSPUTILSLOG(("nsCSPBaseSrc::allows, aKeyWord: %s, a HashOrNonce: %s",
               aKeyword == CSP_HASH ? "hash" : CSP_EnumToKeyword(aKeyword),
               NS_ConvertUTF16toUTF8(aHashOrNonce).get()));
   return false;
 }
 
 /* ====== nsCSPSchemeSrc ===================== */
@@ -466,23 +468,26 @@ nsCSPSchemeSrc::nsCSPSchemeSrc(const nsA
 }
 
 nsCSPSchemeSrc::~nsCSPSchemeSrc()
 {
 }
 
 bool
 nsCSPSchemeSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
-                        bool aReportOnly, bool aUpgradeInsecure) const
+                        bool aReportOnly, bool aUpgradeInsecure, bool aParserCreated) const
 {
   if (CSPUTILSLOGENABLED()) {
     CSPUTILSLOG(("nsCSPSchemeSrc::permits, aUri: %s",
                  aUri->GetSpecOrDefault().get()));
   }
   MOZ_ASSERT((!mScheme.EqualsASCII("")), "scheme can not be the empty string");
+  if (mInvalidated) {
+    return false;
+  }
   return permitsScheme(mScheme, aUri, aReportOnly, aUpgradeInsecure);
 }
 
 bool
 nsCSPSchemeSrc::visit(nsCSPSrcVisitor* aVisitor) const
 {
   return aVisitor->visitSchemeSrc(*this);
 }
@@ -586,23 +591,27 @@ permitsPort(const nsAString& aEnforcemen
   }
 
   // ports do not match, block the load.
   return false;
 }
 
 bool
 nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
-                      bool aReportOnly, bool aUpgradeInsecure) const
+                      bool aReportOnly, bool aUpgradeInsecure, bool aParserCreated) const
 {
   if (CSPUTILSLOGENABLED()) {
     CSPUTILSLOG(("nsCSPHostSrc::permits, aUri: %s",
                  aUri->GetSpecOrDefault().get()));
   }
 
+  if (mInvalidated) {
+    return false;
+  }
+
   // we are following the enforcement rules from the spec, see:
   // http://www.w3.org/TR/CSP11/#match-source-expression
 
   // 4.3) scheme matching: Check if the scheme matches.
   if (!permitsScheme(mScheme, aUri, aReportOnly, aUpgradeInsecure)) {
     return false;
   }
 
@@ -753,100 +762,106 @@ nsCSPHostSrc::appendPath(const nsAString
 {
   mPath.Append(aPath);
 }
 
 /* ===== nsCSPKeywordSrc ===================== */
 
 nsCSPKeywordSrc::nsCSPKeywordSrc(enum CSPKeyword aKeyword)
  : mKeyword(aKeyword)
- , mInvalidated(false)
 {
   NS_ASSERTION((aKeyword != CSP_SELF),
                "'self' should have been replaced in the parser");
 }
 
 nsCSPKeywordSrc::~nsCSPKeywordSrc()
 {
 }
 
 bool
-nsCSPKeywordSrc::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const
+nsCSPKeywordSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
+                         bool aReportOnly, bool aUpgradeInsecure, bool aParserCreated) const
+{
+  // no need to check for invalidated, this will always return false unless
+  // it is an nsCSPKeywordSrc for 'strict-dynamic', which should allow non
+  // parser created scripts.
+  return ((mKeyword == CSP_STRICT_DYNAMIC) && !aParserCreated);
+}
+
+bool
+nsCSPKeywordSrc::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
+                        bool aParserCreated) const
 {
   CSPUTILSLOG(("nsCSPKeywordSrc::allows, aKeyWord: %s, aHashOrNonce: %s, mInvalidated: %s",
               CSP_EnumToKeyword(aKeyword),
+              CSP_EnumToKeyword(mKeyword),
               NS_ConvertUTF16toUTF8(aHashOrNonce).get(),
               mInvalidated ? "yes" : "false"));
-  // if unsafe-inline should be ignored, then bail early
+
   if (mInvalidated) {
-    NS_ASSERTION(mKeyword == CSP_UNSAFE_INLINE,
-                 "should only invalidate unsafe-inline within script-src");
+    // only 'self' and 'unsafe-inline' are keywords that can be ignored. Please note that
+    // the parser already translates 'self' into a uri (see assertion in constructor).
+    MOZ_ASSERT(mKeyword == CSP_UNSAFE_INLINE,
+               "should only invalidate unsafe-inline");
     return false;
   }
-  return mKeyword == aKeyword;
+  // either the keyword allows the load or the policy contains 'strict-dynamic', in which
+  // case we have to make sure the script is not parser created before allowing the load.
+  return ((mKeyword == aKeyword) ||
+          ((mKeyword == CSP_STRICT_DYNAMIC) && !aParserCreated));
 }
 
 bool
 nsCSPKeywordSrc::visit(nsCSPSrcVisitor* aVisitor) const
 {
   return aVisitor->visitKeywordSrc(*this);
 }
 
 void
 nsCSPKeywordSrc::toString(nsAString& outStr) const
 {
-  if (mInvalidated) {
-    MOZ_ASSERT(mKeyword == CSP_UNSAFE_INLINE,
-               "can only ignore 'unsafe-inline' within toString()");
-    return;
-  }
   outStr.AppendASCII(CSP_EnumToKeyword(mKeyword));
 }
 
-void
-nsCSPKeywordSrc::invalidate()
-{
-  mInvalidated = true;
-  MOZ_ASSERT(mKeyword == CSP_UNSAFE_INLINE,
-             "invalidate 'unsafe-inline' only within script-src");
-}
-
 /* ===== nsCSPNonceSrc ==================== */
 
 nsCSPNonceSrc::nsCSPNonceSrc(const nsAString& aNonce)
   : mNonce(aNonce)
 {
 }
 
 nsCSPNonceSrc::~nsCSPNonceSrc()
 {
 }
 
 bool
 nsCSPNonceSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
-                       bool aReportOnly, bool aUpgradeInsecure) const
+                       bool aReportOnly, bool aUpgradeInsecure, bool aParserCreated) const
 {
   if (CSPUTILSLOGENABLED()) {
     CSPUTILSLOG(("nsCSPNonceSrc::permits, aUri: %s, aNonce: %s",
                  aUri->GetSpecOrDefault().get(),
                  NS_ConvertUTF16toUTF8(aNonce).get()));
   }
 
+  // nonces can not be invalidated by strict-dynamic
   return mNonce.Equals(aNonce);
 }
 
 bool
-nsCSPNonceSrc::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const
+nsCSPNonceSrc::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
+                      bool aParserCreated) const
 {
   CSPUTILSLOG(("nsCSPNonceSrc::allows, aKeyWord: %s, a HashOrNonce: %s",
               CSP_EnumToKeyword(aKeyword), NS_ConvertUTF16toUTF8(aHashOrNonce).get()));
 
   if (aKeyword != CSP_NONCE) {
     return false;
   }
+  // nonces can not be invalidated by strict-dynamic
   return mNonce.Equals(aHashOrNonce);
 }
 
 bool
 nsCSPNonceSrc::visit(nsCSPSrcVisitor* aVisitor) const
 {
   return aVisitor->visitNonceSrc(*this);
 }
@@ -869,25 +884,28 @@ nsCSPHashSrc::nsCSPHashSrc(const nsAStri
   ToLowerCase(mAlgorithm);
 }
 
 nsCSPHashSrc::~nsCSPHashSrc()
 {
 }
 
 bool
-nsCSPHashSrc::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const
+nsCSPHashSrc::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
+                     bool aParserCreated) const
 {
   CSPUTILSLOG(("nsCSPHashSrc::allows, aKeyWord: %s, a HashOrNonce: %s",
               CSP_EnumToKeyword(aKeyword), NS_ConvertUTF16toUTF8(aHashOrNonce).get()));
 
   if (aKeyword != CSP_HASH) {
     return false;
   }
 
+  // hashes can not be invalidated by strict-dynamic
+
   // Convert aHashOrNonce to UTF-8
   NS_ConvertUTF16toUTF8 utf8_hash(aHashOrNonce);
 
   nsresult rv;
   nsCOMPtr<nsICryptoHash> hasher;
   hasher = do_CreateInstance("@mozilla.org/security/hash;1", &rv);
   NS_ENSURE_SUCCESS(rv, false);
 
@@ -987,39 +1005,40 @@ nsCSPDirective::~nsCSPDirective()
 {
   for (uint32_t i = 0; i < mSrcs.Length(); i++) {
     delete mSrcs[i];
   }
 }
 
 bool
 nsCSPDirective::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
-                        bool aReportOnly, bool aUpgradeInsecure) const
+                        bool aReportOnly, bool aUpgradeInsecure, bool aParserCreated) const
 {
   if (CSPUTILSLOGENABLED()) {
     CSPUTILSLOG(("nsCSPDirective::permits, aUri: %s",
                  aUri->GetSpecOrDefault().get()));
   }
 
   for (uint32_t i = 0; i < mSrcs.Length(); i++) {
-    if (mSrcs[i]->permits(aUri, aNonce, aWasRedirected, aReportOnly, aUpgradeInsecure)) {
+    if (mSrcs[i]->permits(aUri, aNonce, aWasRedirected, aReportOnly, aUpgradeInsecure, aParserCreated)) {
       return true;
     }
   }
   return false;
 }
 
 bool
-nsCSPDirective::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const
+nsCSPDirective::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
+                       bool aParserCreated) const
 {
   CSPUTILSLOG(("nsCSPDirective::allows, aKeyWord: %s, a HashOrNonce: %s",
               CSP_EnumToKeyword(aKeyword), NS_ConvertUTF16toUTF8(aHashOrNonce).get()));
 
   for (uint32_t i = 0; i < mSrcs.Length(); i++) {
-    if (mSrcs[i]->allows(aKeyword, aHashOrNonce)) {
+    if (mSrcs[i]->allows(aKeyword, aHashOrNonce, aParserCreated)) {
       return true;
     }
   }
   return false;
 }
 
 void
 nsCSPDirective::toString(nsAString& outStr) const
@@ -1302,17 +1321,18 @@ nsRequireSRIForDirective::hasType(nsCont
 
 bool
 nsRequireSRIForDirective::restrictsContentType(const nsContentPolicyType aType) const
 {
   return this->hasType(aType);
 }
 
 bool
-nsRequireSRIForDirective::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const
+nsRequireSRIForDirective::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
+                                 bool aParserCreated) const
 {
   // can only disallow CSP_REQUIRE_SRI_FOR.
   return (aKeyword != CSP_REQUIRE_SRI_FOR);
 }
 
 /* ===== nsCSPPolicy ========================= */
 
 nsCSPPolicy::nsCSPPolicy()
@@ -1332,25 +1352,26 @@ nsCSPPolicy::~nsCSPPolicy()
 }
 
 bool
 nsCSPPolicy::permits(CSPDirective aDir,
                      nsIURI* aUri,
                      bool aSpecific) const
 {
   nsString outp;
-  return this->permits(aDir, aUri, EmptyString(), false, aSpecific, outp);
+  return this->permits(aDir, aUri, EmptyString(), false, aSpecific, false, outp);
 }
 
 bool
 nsCSPPolicy::permits(CSPDirective aDir,
                      nsIURI* aUri,
                      const nsAString& aNonce,
                      bool aWasRedirected,
                      bool aSpecific,
+                     bool aParserCreated,
                      nsAString& outViolatedDirective) const
 {
   if (CSPUTILSLOGENABLED()) {
     CSPUTILSLOG(("nsCSPPolicy::permits, aUri: %s, aDir: %d, aSpecific: %s",
                  aUri->GetSpecOrDefault().get(), aDir,
                  aSpecific ? "true" : "false"));
   }
 
@@ -1358,56 +1379,59 @@ nsCSPPolicy::permits(CSPDirective aDir,
   outViolatedDirective.Truncate();
 
   nsCSPDirective* defaultDir = nullptr;
 
   // Try to find a relevant directive
   // These directive arrays are short (1-5 elements), not worth using a hashtable.
   for (uint32_t i = 0; i < mDirectives.Length(); i++) {
     if (mDirectives[i]->equals(aDir)) {
-      if (!mDirectives[i]->permits(aUri, aNonce, aWasRedirected, mReportOnly, mUpgradeInsecDir)) {
+      if (!mDirectives[i]->permits(aUri, aNonce, aWasRedirected, mReportOnly,
+                                   mUpgradeInsecDir, aParserCreated)) {
         mDirectives[i]->toString(outViolatedDirective);
         return false;
       }
       return true;
     }
     if (mDirectives[i]->isDefaultDirective()) {
       defaultDir = mDirectives[i];
     }
   }
 
   // If the above loop runs through, we haven't found a matching directive.
   // Avoid relooping, just store the result of default-src while looping.
   if (!aSpecific && defaultDir) {
-    if (!defaultDir->permits(aUri, aNonce, aWasRedirected, mReportOnly, mUpgradeInsecDir)) {
+    if (!defaultDir->permits(aUri, aNonce, aWasRedirected, mReportOnly,
+                             mUpgradeInsecDir, aParserCreated)) {
       defaultDir->toString(outViolatedDirective);
       return false;
     }
     return true;
   }
 
   // Nothing restricts this, so we're allowing the load
   // See bug 764937
   return true;
 }
 
 bool
 nsCSPPolicy::allows(nsContentPolicyType aContentType,
                     enum CSPKeyword aKeyword,
-                    const nsAString& aHashOrNonce) const
+                    const nsAString& aHashOrNonce,
+                    bool aParserCreated) const
 {
   CSPUTILSLOG(("nsCSPPolicy::allows, aKeyWord: %s, a HashOrNonce: %s",
               CSP_EnumToKeyword(aKeyword), NS_ConvertUTF16toUTF8(aHashOrNonce).get()));
 
   nsCSPDirective* defaultDir = nullptr;
 
   // Try to find a matching directive
   for (uint32_t i = 0; i < mDirectives.Length(); i++) {
     if (mDirectives[i]->restrictsContentType(aContentType)) {
-      if (mDirectives[i]->allows(aKeyword, aHashOrNonce)) {
+      if (mDirectives[i]->allows(aKeyword, aHashOrNonce, aParserCreated)) {
         return true;
       }
       return false;
     }
     if (mDirectives[i]->isDefaultDirective()) {
       defaultDir = mDirectives[i];
     }
   }
@@ -1420,32 +1444,32 @@ nsCSPPolicy::allows(nsContentPolicyType 
        return true;
      }
     return false;
   }
 
   // If the above loop runs through, we haven't found a matching directive.
   // Avoid relooping, just store the result of default-src while looping.
   if (defaultDir) {
-    return defaultDir->allows(aKeyword, aHashOrNonce);
+    return defaultDir->allows(aKeyword, aHashOrNonce, aParserCreated);
   }
 
   // Allowing the load; see Bug 885433
   // a) inline scripts (also unsafe eval) should only be blocked
   //    if there is a [script-src] or [default-src]
   // b) inline styles should only be blocked
   //    if there is a [style-src] or [default-src]
   return true;
 }
 
 bool
 nsCSPPolicy::allows(nsContentPolicyType aContentType,
                     enum CSPKeyword aKeyword) const
 {
-  return allows(aContentType, aKeyword, NS_LITERAL_STRING(""));
+  return allows(aContentType, aKeyword, NS_LITERAL_STRING(""), false);
 }
 
 void
 nsCSPPolicy::toString(nsAString& outStr) const
 {
   uint32_t length = mDirectives.Length();
   for (uint32_t i = 0; i < length; ++i) {
 
--- a/dom/security/nsCSPUtils.h
+++ b/dom/security/nsCSPUtils.h
@@ -121,32 +121,34 @@ inline CSPDirective CSP_StringToCSPDirec
 // CSPStrKeywords underneath.
 enum CSPKeyword {
   CSP_SELF = 0,
   CSP_UNSAFE_INLINE,
   CSP_UNSAFE_EVAL,
   CSP_NONE,
   CSP_NONCE,
   CSP_REQUIRE_SRI_FOR,
+  CSP_STRICT_DYNAMIC,
   // CSP_LAST_KEYWORD_VALUE always needs to be the last element in the enum
   // because we use it to calculate the size for the char* array.
   CSP_LAST_KEYWORD_VALUE,
   // Putting CSP_HASH after the delimitor, because CSP_HASH is not a valid
   // keyword (hash uses e.g. sha256, sha512) but we use CSP_HASH internally
   // to identify allowed hashes in ::allows.
   CSP_HASH
  };
 
 static const char* CSPStrKeywords[] = {
   "'self'",          // CSP_SELF = 0
   "'unsafe-inline'", // CSP_UNSAFE_INLINE
   "'unsafe-eval'",   // CSP_UNSAFE_EVAL
   "'none'",          // CSP_NONE
   "'nonce-",         // CSP_NONCE
-  "require-sri-for"  // CSP_REQUIRE_SRI_FOR
+  "require-sri-for", // CSP_REQUIRE_SRI_FOR
+  "'strict-dynamic'" // CSP_STRICT_DYNAMIC
   // Remember: CSP_HASH is not supposed to be used
 };
 
 inline const char* CSP_EnumToKeyword(enum CSPKeyword aKey)
 {
   // Make sure all elements in enum CSPKeyword got added to CSPStrKeywords.
   static_assert((sizeof(CSPStrKeywords) / sizeof(CSPStrKeywords[0]) ==
                 static_cast<uint32_t>(CSP_LAST_KEYWORD_VALUE)),
@@ -198,31 +200,41 @@ void CSP_PercentDecodeStr(const nsAStrin
 /* =============== nsCSPSrc ================== */
 
 class nsCSPBaseSrc {
   public:
     nsCSPBaseSrc();
     virtual ~nsCSPBaseSrc();
 
     virtual bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
-                         bool aReportOnly, bool aUpgradeInsecure) const;
-    virtual bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const;
+                         bool aReportOnly, bool aUpgradeInsecure, bool aParserCreated) const;
+    virtual bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
+                        bool aParserCreated) const;
     virtual bool visit(nsCSPSrcVisitor* aVisitor) const = 0;
     virtual void toString(nsAString& outStr) const = 0;
+
+    virtual void invalidate() const
+      { mInvalidated = true; }
+ 
+  protected:
+    // invalidate srcs if 'script-dynamic' is present or also invalidate
+    // unsafe-inline' if nonce- or hash-source specified
+    mutable bool mInvalidated;
+
 };
 
 /* =============== nsCSPSchemeSrc ============ */
 
 class nsCSPSchemeSrc : public nsCSPBaseSrc {
   public:
     explicit nsCSPSchemeSrc(const nsAString& aScheme);
     virtual ~nsCSPSchemeSrc();
 
     bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
-                 bool aReportOnly, bool aUpgradeInsecure) const;
+                 bool aReportOnly, bool aUpgradeInsecure, bool aParserCreated) const;
     bool visit(nsCSPSrcVisitor* aVisitor) const;
     void toString(nsAString& outStr) const;
 
     inline void getScheme(nsAString& outStr) const
       { outStr.Assign(mScheme); };
 
   private:
     nsString mScheme;
@@ -231,17 +243,17 @@ class nsCSPSchemeSrc : public nsCSPBaseS
 /* =============== nsCSPHostSrc ============== */
 
 class nsCSPHostSrc : public nsCSPBaseSrc {
   public:
     explicit nsCSPHostSrc(const nsAString& aHost);
     virtual ~nsCSPHostSrc();
 
     bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
-                 bool aReportOnly, bool aUpgradeInsecure) const;
+                 bool aReportOnly, bool aUpgradeInsecure, bool aParserCreated) const;
     bool visit(nsCSPSrcVisitor* aVisitor) const;
     void toString(nsAString& outStr) const;
 
     void setScheme(const nsAString& aScheme);
     void setPort(const nsAString& aPort);
     void appendPath(const nsAString &aPath);
 
     inline void getScheme(nsAString& outStr) const
@@ -265,67 +277,91 @@ class nsCSPHostSrc : public nsCSPBaseSrc
 
 /* =============== nsCSPKeywordSrc ============ */
 
 class nsCSPKeywordSrc : public nsCSPBaseSrc {
   public:
     explicit nsCSPKeywordSrc(CSPKeyword aKeyword);
     virtual ~nsCSPKeywordSrc();
 
-    bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const;
+    bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
+                bool aParserCreated) const;
+    bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
+                 bool aReportOnly, bool aUpgradeInsecure, bool aParserCreated) const;
     bool visit(nsCSPSrcVisitor* aVisitor) const;
     void toString(nsAString& outStr) const;
-    void invalidate();
 
     inline CSPKeyword getKeyword() const
       { return mKeyword; };
 
+    inline void invalidate() const
+    {
+      // keywords that need to invalidated
+      if (mKeyword == CSP_SELF || mKeyword == CSP_UNSAFE_INLINE) {
+        mInvalidated = true;
+      }
+    }
+
   private:
     CSPKeyword mKeyword;
-    // invalidate 'unsafe-inline' if nonce- or hash-source specified
-    bool       mInvalidated;
 };
 
 /* =============== nsCSPNonceSource =========== */
 
 class nsCSPNonceSrc : public nsCSPBaseSrc {
   public:
     explicit nsCSPNonceSrc(const nsAString& aNonce);
     virtual ~nsCSPNonceSrc();
 
     bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
-                 bool aReportOnly, bool aUpgradeInsecure) const;
-    bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const;
+                 bool aReportOnly, bool aUpgradeInsecure, bool aParserCreated) const;
+    bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
+                bool aParserCreated) const;
     bool visit(nsCSPSrcVisitor* aVisitor) const;
     void toString(nsAString& outStr) const;
 
     inline void getNonce(nsAString& outStr) const
       { outStr.Assign(mNonce); };
 
+    inline void invalidate() const
+    {
+      // overwrite nsCSPBaseSRC::invalidate() and explicitily
+      // do *not* invalidate, because 'strict-dynamic' should
+      // not invalidate nonces.
+    }
+
   private:
     nsString mNonce;
 };
 
 /* =============== nsCSPHashSource ============ */
 
 class nsCSPHashSrc : public nsCSPBaseSrc {
   public:
     nsCSPHashSrc(const nsAString& algo, const nsAString& hash);
     virtual ~nsCSPHashSrc();
 
-    bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const;
+    bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
+                bool aParserCreated) const;
     void toString(nsAString& outStr) const;
     bool visit(nsCSPSrcVisitor* aVisitor) const;
 
     inline void getAlgorithm(nsAString& outStr) const
       { outStr.Assign(mAlgorithm); };
 
     inline void getHash(nsAString& outStr) const
       { outStr.Assign(mHash); };
 
+    inline void invalidate() const
+    {
+      // overwrite nsCSPBaseSRC::invalidate() and explicitily
+      // do *not* invalidate, because 'strict-dynamic' should
+      // not invalidate hashes.
+    }
+
   private:
     nsString mAlgorithm;
     nsString mHash;
 };
 
 /* =============== nsCSPReportURI ============ */
 
 class nsCSPReportURI : public nsCSPBaseSrc {
@@ -376,18 +412,19 @@ class nsCSPSrcVisitor {
 /* =============== nsCSPDirective ============= */
 
 class nsCSPDirective {
   public:
     explicit nsCSPDirective(CSPDirective aDirective);
     virtual ~nsCSPDirective();
 
     virtual bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
-                         bool aReportOnly, bool aUpgradeInsecure) const;
-    virtual bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const;
+                         bool aReportOnly, bool aUpgradeInsecure, bool aParserCreated) const;
+    virtual bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
+                 bool aParserCreated) const;
     virtual void toString(nsAString& outStr) const;
     void toDomCSPStruct(mozilla::dom::CSP& outCSP) const;
 
     virtual void addSrcs(const nsTArray<nsCSPBaseSrc*>& aSrcs)
       { mSrcs = aSrcs; }
 
     virtual bool restrictsContentType(nsContentPolicyType aContentType) const;
 
@@ -433,23 +470,24 @@ class nsCSPChildSrcDirective : public ns
 /* =============== nsBlockAllMixedContentDirective === */
 
 class nsBlockAllMixedContentDirective : public nsCSPDirective {
   public:
     explicit nsBlockAllMixedContentDirective(CSPDirective aDirective);
     ~nsBlockAllMixedContentDirective();
 
     bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
-                 bool aReportOnly, bool aUpgradeInsecure) const
+                 bool aReportOnly, bool aUpgradeInsecure, bool aParserCreated) const
       { return false; }
 
     bool permits(nsIURI* aUri) const
       { return false; }
 
-    bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const
+    bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
+                bool aParserCreated) const
       { return false; }
 
     void toString(nsAString& outStr) const;
 
     void addSrcs(const nsTArray<nsCSPBaseSrc*>& aSrcs)
       {  MOZ_ASSERT(false, "block-all-mixed-content does not hold any srcs"); }
 };
 
@@ -485,23 +523,24 @@ class nsBlockAllMixedContentDirective : 
  *     gets upgraded from ws to wss.
  */
 class nsUpgradeInsecureDirective : public nsCSPDirective {
   public:
     explicit nsUpgradeInsecureDirective(CSPDirective aDirective);
     ~nsUpgradeInsecureDirective();
 
     bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
-                 bool aReportOnly, bool aUpgradeInsecure) const
+                 bool aReportOnly, bool aUpgradeInsecure, bool aParserCreated) const
       { return false; }
 
     bool permits(nsIURI* aUri) const
       { return false; }
 
-    bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const
+    bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
+                bool aParserCreated) const
       { return false; }
 
     void toString(nsAString& outStr) const;
 
     void addSrcs(const nsTArray<nsCSPBaseSrc*>& aSrcs)
       {  MOZ_ASSERT(false, "upgrade-insecure-requests does not hold any srcs"); }
 };
 
@@ -513,17 +552,18 @@ class nsRequireSRIForDirective : public 
     ~nsRequireSRIForDirective();
 
     void toString(nsAString& outStr) const;
 
     void addType(nsContentPolicyType aType)
       { mTypes.AppendElement(aType); }
     bool hasType(nsContentPolicyType aType) const;
     bool restrictsContentType(nsContentPolicyType aType) const;
-    bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const;
+    bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
+                bool aParserCreated) const;
 
   private:
     nsTArray<nsContentPolicyType> mTypes;
 };
 
 /* =============== nsCSPPolicy ================== */
 
 class nsCSPPolicy {
@@ -531,23 +571,25 @@ class nsCSPPolicy {
     nsCSPPolicy();
     virtual ~nsCSPPolicy();
 
     bool permits(CSPDirective aDirective,
                  nsIURI* aUri,
                  const nsAString& aNonce,
                  bool aWasRedirected,
                  bool aSpecific,
+                 bool aParserCreated,
                  nsAString& outViolatedDirective) const;
     bool permits(CSPDirective aDir,
                  nsIURI* aUri,
                  bool aSpecific) const;
     bool allows(nsContentPolicyType aContentType,
                 enum CSPKeyword aKeyword,
-                const nsAString& aHashOrNonce) const;
+                const nsAString& aHashOrNonce,
+                bool aParserCreated) const;
     bool allows(nsContentPolicyType aContentType,
                 enum CSPKeyword aKeyword) const;
     void toString(nsAString& outStr) const;
     void toDomCSPStruct(mozilla::dom::CSP& outCSP) const;
 
     inline void addDirective(nsCSPDirective* aDir)
       { mDirectives.AppendElement(aDir); }
 
--- a/dom/security/test/unit/test_csp_reports.js
+++ b/dom/security/test/unit/test_csp_reports.js
@@ -108,16 +108,17 @@ function run_test() {
                                "/foo/self");
 
   // test that inline script violations cause a report.
   makeTest(0, {"blocked-uri": "self"}, false,
       function(csp) {
         let inlineOK = true;
         inlineOK = csp.getAllowsInline(Ci.nsIContentPolicy.TYPE_SCRIPT,
                                        "", // aNonce
+                                       false, // aParserCreated
                                        "", // aContent
                                        0); // aLineNumber
 
         // this is not a report only policy, so it better block inline scripts
         do_check_false(inlineOK);
       });
 
   // test that eval violations cause a report.
@@ -154,16 +155,17 @@ function run_test() {
       });
 
   // test that inline script violations cause a report in report-only policy
   makeTest(3, {"blocked-uri": "self"}, true,
       function(csp) {
         let inlineOK = true;
         inlineOK = csp.getAllowsInline(Ci.nsIContentPolicy.TYPE_SCRIPT,
                                        "", // aNonce
+                                       false, // aParserCreated
                                        "", // aContent
                                        0); // aLineNumber
 
         // this is a report only policy, so it better allow inline scripts
         do_check_true(inlineOK);
       });
 
   // test that eval violations cause a report in report-only policy
--- a/layout/style/nsStyleUtil.cpp
+++ b/layout/style/nsStyleUtil.cpp
@@ -768,14 +768,16 @@ nsStyleUtil::CSPAllowsInlineStyle(nsICon
   // query the nonce
   nsAutoString nonce;
   if (aContent) {
     aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::nonce, nonce);
   }
 
   bool allowInlineStyle = true;
   rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_STYLESHEET,
-                            nonce, aStyleText, aLineNumber,
+                            nonce,
+                            false, // aParserCreated only applies to scripts
+                            aStyleText, aLineNumber,
                             &allowInlineStyle);
   NS_ENSURE_SUCCESS(rv, false);
 
   return allowInlineStyle;
 }