validateCspPolicyString()

in src/parsers/manifestjson.js [1170:1247]


  validateCspPolicyString(policy, manifestPropName) {
    if (typeof policy !== 'string') {
      return;
    }

    const directives = parseCspPolicy(policy);

    // The order is important here, 'default-src' needs to be before
    // 'script-src' to ensure it can overwrite default-src security policies
    const candidates = [
      'default-src',
      'script-src',
      'script-src-elem',
      'script-src-attr',
      'worker-src',
    ];

    const isSecureCspValue = (value) => CSP_KEYWORD_RE.test(value);

    // A missing default-src directive is very permissive, thus insecure:
    let insecureSrcDirective = !directives['default-src'];
    let warnInsecureCsp = insecureSrcDirective;
    let warnInsecureEval = false;

    for (let i = 0; i < candidates.length; i++) {
      /* eslint-disable no-continue */
      const candidate = candidates[i];
      if (Object.prototype.hasOwnProperty.call(directives, candidate)) {
        const values = directives[candidate];

        // If the 'default-src' is insecure, check whether the 'script-src'
        // makes it secure, ie 'script-src: self;'
        //
        // NOTE: this is not yet considering script-src-elem and script-src-attr,
        // and it can't be extended to them as is, each of them on their
        // own would not fully cover an insecure src directive and they would
        // need to be appropriately combined with other directives.
        if (
          insecureSrcDirective &&
          candidate === 'script-src' &&
          values.every(isSecureCspValue)
        ) {
          insecureSrcDirective = false;
          warnInsecureCsp = false;
          continue;
        }

        for (const value of values) {
          // Add a more detailed message for unsafe-eval to avoid confusion
          // about why it's forbidden.
          if (value === "'unsafe-eval'") {
            warnInsecureEval = true;
            continue;
          }

          if (!isSecureCspValue(value)) {
            warnInsecureCsp = true;
            // everything else looks like something we don't understand
            // / support otherwise is invalid so let's warn about that.
            if (candidate === 'default-src') {
              // Remember insecure 'default-src' to check whether a later
              // 'script-src' makes it secure
              insecureSrcDirective = true;
            }
            continue;
          }
        }
      }
    }
    if (warnInsecureEval) {
      this.collector.addWarning(
        messages.manifestCspUnsafeEval(manifestPropName)
      );
    }
    if (warnInsecureCsp) {
      this.collector.addWarning(messages.manifestCsp(manifestPropName));
    }
  }