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 321518 22f5124ac4b6ba1e080081ac659871d178a9c929
parent 321517 fe3fe09d24c8619d7b4a71aa6c5fccdb05f98636
child 321519 908b79c3788827e44af80f75f99396ec7f626ecb
push id83632
push usermozilla@christophkerschbaumer.com
push dateTue, 08 Nov 2016 15:52:17 +0000
treeherdermozilla-inbound@f3c84b104987 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdveditz, freddyb
bugs1299483
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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;
 }