Dynamic Import Host Adjustment

Stage 2
Spec source, output
Tests TODO
Champion @mikesamuel
Reviewers @bakkot, @erights, @bmeck

Trusted Types guards sensitive APIs; it double checks that values have been trusted by policy code before performing operations that cannot be undone.

The dynamic import operator, import(...), loads code and initializes modules. Loading code from an untrustworthy source is an operation that cannot be undone.

This adjusts the host callout which enables dynamic loading. With it:

  1. The host receives the original specifier (before it is stringified) so can use runtime type information to decide whether to allow code loading to proceed.
  2. The host callout can control stringification and convey the result to FinishDynamicImport to avoid repeated stringification, and to integrate with default policies.

Testing

Tests, to be written, will be implemented as web-platform-tests and will focus on the following properties:

  1. Polymorphic objects stringified once. Something like

    importScripts("/resources/testharness.js");
    
    test(
      () => {
        let stringifyCount = 0;
        import({
          toString() {
            let specifier = `data:text/javascript,export default ${ stringifyCount }`;
            ++stringifyCount;
            return specifier;
          }
        })
        .then(
          (defaultExport) => {
            assert_equals(stringifyCount, 1);
            assert_equals(defaultExport, 0);
          },
          (err) => {
            assert_equals(err, null);
          })
        .finally(done);
      },
      'DynamicImportStringifiesSpecifierOnce');
    
  2. The above, with coverage for both null and non-null referencing modules.

  3. Tests specific to trusted-types host implementation.

See also webappsec-csp #243 on import('data:...') as CSP bypass.