diff --git a/doc/api/policy.md b/doc/api/policy.md
index e5387f49c0306d..4af900f2e9b406 100644
--- a/doc/api/policy.md
+++ b/doc/api/policy.md
@@ -196,4 +196,93 @@ module.exports = function fn(...args) {
 };
 ```
 
+### Scopes
+
+Use the `"scopes"` field of a manifest to set configuration for many resources
+at once. The `"scopes"` field works by matching resources by their segments.
+If a scope or resource includes `"cascade": true` unknown specifiers will
+be searched for in their containing scope. The containing scope for cascading
+is found by recursively reducing the resource URL by removing segments for
+[special schemes][], keeping trailing `"/"` suffixes and removing the query and
+hash fragment. This leads to the eventual reduction of the URL to its origin.
+If the URL is non-special the scope will be located by the URL's origin. If no
+scope is found for the origin or in the case of opaque origins, a protocol
+string can be used as a scope.
+
+Note, `blob:` URLs adopt their origin from the path they contain, and so a scope
+of `"blob:https://nodejs.org"` will have no effect since no URL can have an
+origin of `blob:https://nodejs.org`; URLs starting with
+`blob:https://nodejs.org/` will use `https://nodejs.org` for its origin and
+thus `https:` for its protocol scope. For opaque origin `blob:` URLs they will
+have `blob:` for their protocol scope since they do not adopt origins.
+
+#### Integrity Using Scopes
+
+Setting an integrity to `true` on a scope will set the integrity for any
+resource not found in the manifest to `true`.
+
+Setting an integrity to `null` on a scope will set the integrity for any
+resource not found in the manifest to fail matching.
+
+Not including an integrity is the same as setting the integrity to `null`.
+
+`"cascade"` for integrity checks will be ignored if `"integrity"` is explicitly
+set.
+
+The following example allows loading any file:
+
+```json
+{
+  "scopes": {
+    "file:": {
+      "integrity": true
+    }
+  }
+}
+```
+
+#### Dependency Redirection Using Scopes
+
+The following example, would allow access to `fs` for all resources within
+`./app/`:
+
+```json
+{
+  "resources": {
+    "./app/checked.js": {
+      "cascade": true,
+      "integrity": true
+    }
+  },
+  "scopes": {
+    "./app/": {
+      "dependencies": {
+        "fs": true
+      }
+    }
+  }
+}
+```
+
+The following example, would allow access to `fs` for all `data:` resources:
+
+```json
+{
+  "resources": {
+    "data:text/javascript,import('fs');": {
+      "cascade": true,
+      "integrity": true
+    }
+  },
+  "scopes": {
+    "data:": {
+      "dependencies": {
+        "fs": true
+      }
+    }
+  }
+}
+```
+
 [relative url string]: https://url.spec.whatwg.org/#relative-url-with-fragment-string
+[special schemes]: https://url.spec.whatwg.org/#special-scheme
diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js
index 845f8d8f9aa21d..058cb9b0f3d21d 100644
--- a/lib/internal/modules/cjs/loader.js
+++ b/lib/internal/modules/cjs/loader.js
@@ -47,8 +47,8 @@ const {
   SafeWeakMap,
   String,
   StringPrototypeEndsWith,
-  StringPrototypeIndexOf,
   StringPrototypeLastIndexOf,
+  StringPrototypeIndexOf,
   StringPrototypeMatch,
   StringPrototypeSlice,
   StringPrototypeStartsWith,
@@ -82,8 +82,9 @@ const {
 const { getOptionValue } = require('internal/options');
 const preserveSymlinks = getOptionValue('--preserve-symlinks');
 const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
-const manifest = getOptionValue('--experimental-policy') ?
-  require('internal/process/policy').manifest :
+// Do not eagerly grab .manifest, it may be in TDZ
+const policy = getOptionValue('--experimental-policy') ?
+  require('internal/process/policy') :
   null;
 const { compileFunction } = internalBinding('contextify');
 
@@ -1043,10 +1044,10 @@ function wrapSafe(filename, content, cjsModuleInstance) {
 Module.prototype._compile = function(content, filename) {
   let moduleURL;
   let redirects;
-  if (manifest) {
+  if (policy?.manifest) {
     moduleURL = pathToFileURL(filename);
-    redirects = manifest.getRedirector(moduleURL);
-    manifest.assertIntegrity(moduleURL, content);
+    redirects = policy.manifest.getDependencyMapper(moduleURL);
+    policy.manifest.assertIntegrity(moduleURL, content);
   }
 
   maybeCacheSourceMap(filename, content, this);
@@ -1115,9 +1116,9 @@ Module._extensions['.js'] = function(module, filename) {
 Module._extensions['.json'] = function(module, filename) {
   const content = fs.readFileSync(filename, 'utf8');
 
-  if (manifest) {
+  if (policy?.manifest) {
     const moduleURL = pathToFileURL(filename);
-    manifest.assertIntegrity(moduleURL, content);
+    policy.manifest.assertIntegrity(moduleURL, content);
   }
 
   try {
@@ -1131,10 +1132,10 @@ Module._extensions['.json'] = function(module, filename) {
 
 // Native extension for .node
 Module._extensions['.node'] = function(module, filename) {
-  if (manifest) {
+  if (policy?.manifest) {
     const content = fs.readFileSync(filename);
     const moduleURL = pathToFileURL(filename);
-    manifest.assertIntegrity(moduleURL, content);
+    policy.manifest.assertIntegrity(moduleURL, content);
   }
   // Be aware this doesn't use `content`
   return process.dlopen(module, path.toNamespacedPath(filename));
diff --git a/lib/internal/modules/esm/get_source.js b/lib/internal/modules/esm/get_source.js
index 5e2cc3e09e7687..54dbd029fcfc22 100644
--- a/lib/internal/modules/esm/get_source.js
+++ b/lib/internal/modules/esm/get_source.js
@@ -1,8 +1,9 @@
 'use strict';
 
 const { getOptionValue } = require('internal/options');
-const manifest = getOptionValue('--experimental-policy') ?
-  require('internal/process/policy').manifest :
+// Do not eagerly grab .manifest, it may be in TDZ
+const policy = getOptionValue('--experimental-policy') ?
+  require('internal/process/policy') :
   null;
 
 const { Buffer } = require('buffer');
@@ -33,8 +34,8 @@ async function defaultGetSource(url, { format } = {}, defaultGetSource) {
   } else {
     throw new ERR_INVALID_URL_SCHEME(['file', 'data']);
   }
-  if (manifest) {
-    manifest.assertIntegrity(parsed, source);
+  if (policy?.manifest) {
+    policy.manifest.assertIntegrity(parsed, source);
   }
   return { source };
 }
diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js
index d58eac5f1c10cb..0a828867692473 100644
--- a/lib/internal/modules/esm/resolve.js
+++ b/lib/internal/modules/esm/resolve.js
@@ -30,8 +30,9 @@ const {
   Stats,
 } = require('fs');
 const { getOptionValue } = require('internal/options');
-const manifest = getOptionValue('--experimental-policy') ?
-  require('internal/process/policy').manifest :
+// Do not eagerly grab .manifest, it may be in TDZ
+const policy = getOptionValue('--experimental-policy') ?
+  require('internal/process/policy') :
   null;
 const { sep, relative } = require('path');
 const preserveSymlinks = getOptionValue('--preserve-symlinks');
@@ -714,8 +715,8 @@ function resolveAsCommonJS(specifier, parentURL) {
 
 function defaultResolve(specifier, context = {}, defaultResolveUnused) {
   let { parentURL, conditions } = context;
-  if (manifest) {
-    const redirects = manifest.getRedirector(parentURL);
+  if (parentURL && policy?.manifest) {
+    const redirects = policy.manifest.getDependencyMapper(parentURL);
     if (redirects) {
       const { resolve, reaction } = redirects;
       const destination = resolve(specifier, new SafeSet(conditions));
diff --git a/lib/internal/modules/package_json_reader.js b/lib/internal/modules/package_json_reader.js
index 25edfee027c35b..4a2b0e6ddb3ed8 100644
--- a/lib/internal/modules/package_json_reader.js
+++ b/lib/internal/modules/package_json_reader.js
@@ -7,6 +7,8 @@ const { toNamespacedPath } = require('path');
 
 const cache = new SafeMap();
 
+let manifest;
+
 /**
  *
  * @param {string} jsonPath
@@ -22,10 +24,12 @@ function read(jsonPath) {
   const result = { string, containsKeys };
   const { getOptionValue } = require('internal/options');
   if (string !== undefined) {
-    const manifest = getOptionValue('--experimental-policy') ?
-      require('internal/process/policy').manifest :
-      null;
-    if (manifest) {
+    if (manifest === undefined) {
+      manifest = getOptionValue('--experimental-policy') ?
+        require('internal/process/policy').manifest :
+        null;
+    }
+    if (manifest !== null) {
       const jsonURL = pathToFileURL(jsonPath);
       manifest.assertIntegrity(jsonURL, string);
     }
diff --git a/lib/internal/policy/manifest.js b/lib/internal/policy/manifest.js
index 920790a22ed46e..71dc3d78ab09e4 100644
--- a/lib/internal/policy/manifest.js
+++ b/lib/internal/policy/manifest.js
@@ -11,15 +11,13 @@ const {
   ObjectSetPrototypeOf,
   RegExpPrototypeTest,
   SafeMap,
+  SafeSet,
+  Symbol,
   uncurryThis,
 } = primordials;
-const {
-  compositeKey
-} = require('internal/util/compositekey');
 const {
   canBeRequiredByUsers
 } = require('internal/bootstrap/loaders').NativeModule;
-
 const {
   ERR_MANIFEST_ASSERT_INTEGRITY,
   ERR_MANIFEST_INTEGRITY_MISMATCH,
@@ -43,6 +41,18 @@ const shouldAbortOnUncaughtException =
   getOptionValue('--abort-on-uncaught-exception');
 const { abort, exit, _rawDebug } = process;
 
+// From https://url.spec.whatwg.org/#special-scheme
+const SPECIAL_SCHEMES = new SafeSet([
+  'file:',
+  'ftp:',
+  'http:',
+  'https:',
+  'ws:',
+  'wss:',
+]);
+
+const kCascade = Symbol('cascade');
+
 function REACTION_THROW(error) {
   throw error;
 }
@@ -58,10 +68,33 @@ function REACTION_EXIT(error) {
 function REACTION_LOG(error) {
   _rawDebug(error.stack);
 }
+/**
+ * @typedef {(specifier: string) => true | URL} DependencyMapper
+ * @typedef {Record<string, string> | true} DependencyMap
+ * @typedef {true | string | SRI[]} Integrity
+ */
 
 class Manifest {
   /**
-   * @type {Map<string, true | string | SRI[]>}
+   * @type {Map<string, DependencyMapper>}
+   *
+   * Used to compare a resource to the content body at the resource.
+   * `true` is used to signify that all integrities are allowed, otherwise,
+   * SRI strings are parsed to compare with the body.
+   *
+   * Separate from #resourceDependencies due to conflicts with things like
+   * `blob:` being both a scope and a resource potentially as well as
+   * `file:` being parsed to `file:///` instead of remaining host neutral.
+   */
+  #scopeDependencies = new SafeMap();
+  /**
+   * @type {Map<string, true | null | 'cascade'>}
+   *
+   * Used to allow arbitrary loading within a scope
+   */
+  #scopeIntegrities = new SafeMap();
+  /**
+   * @type {Map<string, Integrity>}
    *
    * Used to compare a resource to the content body at the resource.
    * `true` is used to signify that all integrities are allowed, otherwise,
@@ -72,14 +105,9 @@ class Manifest {
    * This avoids needing to parse all SRI strings at startup even
    * if some never end up being used.
    */
-  #integrities = new SafeMap();
+  #resourceIntegrities = new SafeMap();
   /**
-   * @type {
-      Map<
-        string,
-        (specifier: string, conditions: Set<string>) => true | null | URL
-      >
-    }
+   * @type {Map<string, DependencyMapper>}
    *
    * Used to find where a dependency is located.
    *
@@ -90,7 +118,7 @@ class Manifest {
    * The functions return `null` to signify that a dependency is
    * not found
    */
-  #dependencies = new SafeMap();
+  #resourceDependencies = new SafeMap();
   /**
    * @type {(err: Error) => void}
    *
@@ -110,8 +138,9 @@ class Manifest {
    * @param {string} manifestURL
    */
   constructor(obj, manifestURL) {
-    const integrities = this.#integrities;
-    const dependencies = this.#dependencies;
+    const scopes = this.#scopeDependencies;
+    const integrities = this.#resourceIntegrities;
+    const dependencies = this.#resourceDependencies;
     let reaction = REACTION_THROW;
 
     if (obj.onerror) {
@@ -127,34 +156,207 @@ class Manifest {
     }
 
     this.#reaction = reaction;
-    const manifestEntries = ObjectEntries(obj.resources);
+    const jsonResourcesEntries = ObjectEntries(obj.resources ?? {});
+    const jsonScopesEntries = ObjectEntries(obj.scopes ?? {});
+
+    function searchDependencies(resourceHREF, target, conditions) {
+      if (
+        target &&
+        typeof target === 'object' &&
+        !ArrayIsArray(target)
+      ) {
+        const keys = ObjectKeys(target);
+        for (let i = 0; i < keys.length; i++) {
+          const key = keys[i];
+          if (conditions.has(key)) {
+            const ret = searchDependencies(
+              resourceHREF,
+              target[key],
+              conditions);
+            if (ret != null) {
+              return ret;
+            }
+          }
+        }
+      } else if (typeof target === 'string') {
+        return target;
+      } else if (target === true) {
+        return target;
+      } else {
+        throw new ERR_MANIFEST_INVALID_RESOURCE_FIELD(
+          resourceHREF,
+          'dependencies');
+      }
+      return null;
+    }
+
+    /**
+     * @param {string} resourceHREF
+     * @param {{[key: string]: string | true}} dependencyMap
+     * @param {boolean} cascade
+     * @returns {DependencyMapper}
+     */
+    const createDependencyMapper = (
+      resourceHREF,
+      dependencyMap,
+      cascade
+    ) => {
+      let parentDeps;
+      return (toSpecifier, conditions) => {
+        if (toSpecifier in dependencyMap !== true) {
+          if (cascade === true) {
+            let scopeHREF;
+            if (typeof parentDeps === 'undefined') {
+              do {
+                scopeHREF = this.#findScopeHREF(resourceHREF);
+              } while (
+                scopeHREF !== null &&
+                scopes.has(scopeHREF) !== true
+              );
+            }
+            if (scopeHREF === null) {
+              parentDeps = () => null;
+            } else {
+              parentDeps = scopes.get(scopeHREF);
+            }
+            return parentDeps(toSpecifier);
+          }
+          return null;
+        }
+        const to = searchDependencies(
+          resourceHREF,
+          dependencyMap[toSpecifier],
+          conditions);
+        if (to === true) {
+          return true;
+        }
+        if (parsedURLs.has(to)) {
+          return parsedURLs.get(to);
+        } else if (canBeRequiredByUsers(to)) {
+          const href = `node:${to}`;
+          const resolvedURL = new URL(href);
+          parsedURLs.set(to, resolvedURL);
+          parsedURLs.set(href, resolvedURL);
+          return resolvedURL;
+        } else if (RegExpPrototypeTest(kRelativeURLStringPattern, to)) {
+          const resolvedURL = new URL(to, manifestURL);
+          const href = resourceHREF;
+          parsedURLs.set(to, resolvedURL);
+          parsedURLs.set(href, resolvedURL);
+          return resolvedURL;
+        }
+        const resolvedURL = new URL(to);
+        const href = resourceHREF;
+        parsedURLs.set(to, resolvedURL);
+        parsedURLs.set(href, resolvedURL);
+        return resolvedURL;
+      };
+    };
 
+    /**
+     * Stores URLs keyed by string specifier relative to the manifest
+     * @type {Map<string, URL>}
+     */
     const parsedURLs = new SafeMap();
-    for (let i = 0; i < manifestEntries.length; i++) {
-      let resourceHREF = manifestEntries[i][0];
-      const originalHREF = resourceHREF;
-      let resourceURL;
-      if (parsedURLs.has(resourceHREF)) {
-        resourceURL = parsedURLs.get(resourceHREF);
-        resourceHREF = resourceURL.href;
+
+    /**
+     * Resolves a valid url string against the manifest
+     * @param {string} originalHREF
+     * @returns {string}
+     */
+    const resolve = (originalHREF) => {
+      if (parsedURLs.has(originalHREF)) {
+        return parsedURLs.get(originalHREF).href;
       } else if (
-        RegExpPrototypeTest(kRelativeURLStringPattern, resourceHREF)
+        RegExpPrototypeTest(kRelativeURLStringPattern, originalHREF)
       ) {
-        resourceURL = new URL(resourceHREF, manifestURL);
-        resourceHREF = resourceURL.href;
+        const resourceURL = new URL(originalHREF, manifestURL);
+        const resourceHREF = resourceURL.href;
         parsedURLs.set(originalHREF, resourceURL);
-        parsedURLs.set(resourceHREF, resourceURL);
+        parsedURLs.set(resourceURL.href, resourceURL);
+        return resourceHREF;
       }
-      let integrity = manifestEntries[i][1].integrity;
-      if (!integrity) integrity = null;
-      if (integrity != null) {
-        debug('Manifest contains integrity for url %s', originalHREF);
-        if (typeof integrity === 'string') {
-          if (integrities.has(resourceHREF)) {
-            if (integrities.get(resourceHREF) !== integrity) {
-              throw new ERR_MANIFEST_INTEGRITY_MISMATCH(resourceURL);
-            }
+      const resourceURL = new URL(originalHREF);
+      const resourceHREF = resourceURL.href;
+      parsedURLs.set(originalHREF, resourceURL);
+      return resourceHREF;
+    };
+
+    /**
+     * @param {string} resourceHREF
+     * @param {DependencyMap} dependencyMap
+     * @param {boolean} cascade
+     * @param {Map<string, DependencyMapper>} store
+     */
+    const insertDependencyMap = (
+      resourceHREF,
+      dependencyMap,
+      cascade,
+      store
+    ) => {
+      if (cascade !== undefined && typeof cascade !== 'boolean') {
+        throw new ERR_MANIFEST_INVALID_RESOURCE_FIELD(
+          resourceHREF,
+          'cascade');
+      }
+      if (dependencyMap === null || dependencyMap === undefined) {
+        dependencyMap = ObjectCreate(null);
+      }
+      if (
+        typeof dependencyMap === 'object' &&
+        !ArrayIsArray(dependencyMap)
+      ) {
+        const dependencyRedirectList = createDependencyMapper(
+          resourceHREF,
+          dependencyMap,
+          cascade);
+        store.set(resourceHREF, dependencyRedirectList);
+        return;
+      } else if (dependencyMap === true) {
+        const arbitraryDependencies = /** @type {()=>true} */() => true;
+        store.set(resourceHREF, arbitraryDependencies);
+        return;
+      }
+      throw new ERR_MANIFEST_INVALID_RESOURCE_FIELD(
+        resourceHREF,
+        'dependencies');
+    };
+    /**
+     * Does a special allowance for scopes to be non-valid URLs
+     * that are only protocol strings
+     * @param {string} resourceHREF
+     * @returns {string}
+     */
+    const protocolOrResolve = (resourceHREF) => {
+      if (resourceHREF.endsWith(':')) {
+        // URL parse will trim these anyway, save the compute
+        resourceHREF = resourceHREF.replace(
+          // eslint-disable-next-line
+          /^[\x00-\x1F\x20]|\x09\x0A\x0D|[\x00-\x1F\x20]$/g,
+          ''
+        );
+        if (/^[a-zA-Z][a-zA-Z+\-.]*:$/.test(resourceHREF)) {
+          return resourceHREF;
+        }
+      }
+      return resolve(resourceHREF);
+    };
+
+    for (let i = 0; i < jsonResourcesEntries.length; i++) {
+      const [originalHREF, resourceDescriptor] = jsonResourcesEntries[i];
+      const cascade = resourceDescriptor.cascade;
+      const dependencyMap = resourceDescriptor.dependencies;
+      const resourceHREF = resolve(originalHREF);
+
+      const integrity = resourceDescriptor.integrity;
+      if (typeof integrity !== 'undefined') {
+        debug('Manifest contains integrity for resource %s', originalHREF);
+        if (integrities.has(resourceHREF)) {
+          if (integrities.get(resourceHREF) !== integrity) {
+            throw new ERR_MANIFEST_INTEGRITY_MISMATCH(resourceHREF);
           }
+        }
+        if (typeof integrity === 'string') {
           integrities.set(resourceHREF, integrity);
         } else if (integrity === true) {
           integrities.set(resourceHREF, true);
@@ -163,127 +365,114 @@ class Manifest {
             resourceHREF,
             'integrity');
         }
+      } else {
+        integrities.set(resourceHREF, cascade ? kCascade : null);
       }
+      insertDependencyMap(resourceHREF, dependencyMap, cascade, dependencies);
+    }
 
-      let dependencyMap = manifestEntries[i][1].dependencies;
-      if (dependencyMap === null || dependencyMap === undefined) {
-        dependencyMap = ObjectCreate(null);
-      }
-      if (typeof dependencyMap === 'object' && !ArrayIsArray(dependencyMap)) {
-        function searchDependencies(target, conditions) {
-          if (
-            target &&
-            typeof target === 'object' &&
-            !ArrayIsArray(target)
-          ) {
-            const keys = ObjectKeys(target);
-            for (let i = 0; i < keys.length; i++) {
-              const key = keys[i];
-              if (conditions.has(key)) {
-                const ret = searchDependencies(target[key], conditions);
-                if (ret != null) {
-                  return ret;
-                }
-              }
-            }
-          } else if (typeof target === 'string') {
-            return target;
-          } else if (target === true) {
-            return target;
-          } else {
-            throw new ERR_MANIFEST_INVALID_RESOURCE_FIELD(
-              resourceHREF,
-              'dependencies');
+    const scopeIntegrities = this.#scopeIntegrities;
+    for (let i = 0; i < jsonScopesEntries.length; i++) {
+      const [originalHREF, scopeDescriptor] = jsonScopesEntries[i];
+      const integrity = scopeDescriptor.integrity;
+      const cascade = scopeDescriptor.cascade;
+      const dependencyMap = scopeDescriptor.dependencies;
+      const resourceHREF = protocolOrResolve(originalHREF);
+      if (typeof integrity !== 'undefined') {
+        debug('Manifest contains integrity for scope %s', originalHREF);
+        if (scopeIntegrities.has(resourceHREF)) {
+          if (scopeIntegrities.get(resourceHREF) !== integrity) {
+            throw new ERR_MANIFEST_INTEGRITY_MISMATCH(resourceHREF);
           }
-          return null;
         }
-        // This is used so we don't traverse this every time
-        // in theory we can delete parts of the dep map once this is populated
-        const localMappings = new SafeMap();
-        /**
-         * @returns {true | null | URL}
-         */
-        const dependencyRedirectList = (specifier, conditions) => {
-          const key = compositeKey([localMappings, specifier, ...conditions]);
-          if (localMappings.has(key)) {
-            return localMappings.get(key);
-          }
-          if (specifier in dependencyMap !== true) {
-            localMappings.set(key, null);
-            return null;
-          }
-          const target = searchDependencies(
-            dependencyMap[specifier],
-            conditions);
-          if (target === true) {
-            localMappings.set(key, true);
-            return true;
-          }
-          if (typeof target !== 'string') {
-            localMappings.set(key, null);
-            return null;
-          }
-          if (parsedURLs.has(target)) {
-            const parsed = parsedURLs.get(target);
-            localMappings.set(key, parsed);
-            return parsed;
-          } else if (canBeRequiredByUsers(target)) {
-            const href = `node:${target}`;
-            const resolvedURL = new URL(href);
-            parsedURLs.set(target, resolvedURL);
-            parsedURLs.set(href, resolvedURL);
-            localMappings.set(key, resolvedURL);
-            return resolvedURL;
-          } else if (RegExpPrototypeTest(kRelativeURLStringPattern, target)) {
-            const resolvedURL = new URL(target, manifestURL);
-            const href = resourceURL.href;
-            parsedURLs.set(target, resolvedURL);
-            parsedURLs.set(href, resolvedURL);
-            localMappings.set(key, resolvedURL);
-            return resolvedURL;
-          }
-          const resolvedURL = new URL(target);
-          const href = resolvedURL.href;
-          parsedURLs.set(target, resolvedURL);
-          parsedURLs.set(href, resolvedURL);
-          localMappings.set(key, resolvedURL);
-          return resolvedURL;
-        };
-        dependencies.set(resourceHREF, dependencyRedirectList);
-      } else if (dependencyMap === true) {
-        const arbitraryDependencies = () => true;
-        dependencies.set(resourceHREF, arbitraryDependencies);
+        if (integrity === true) {
+          scopeIntegrities.set(resourceHREF, true);
+        } else {
+          throw new ERR_MANIFEST_INVALID_RESOURCE_FIELD(
+            resourceHREF,
+            'integrity');
+        }
       } else {
-        throw new ERR_MANIFEST_INVALID_RESOURCE_FIELD(
-          resourceHREF,
-          'dependencies');
+        scopeIntegrities.set(resourceHREF, cascade ? kCascade : null);
       }
+      insertDependencyMap(resourceHREF, dependencyMap, cascade, scopes);
     }
+
     ObjectFreeze(this);
   }
 
-  getRedirector(requester) {
-    requester = `${requester}`;
-    const dependencies = this.#dependencies;
-    if (dependencies.has(requester)) {
-      return {
-        resolve: (specifier, conditions) => dependencies.get(requester)(
-          `${specifier}`,
-          conditions
-        ),
-        reaction: this.#reaction
-      };
+  /**
+   * Finds the longest key within `this.#scopeDependencies` that covers a
+   * specific HREF
+   * @param {string} href
+   * @returns {null | string}
+   */
+  #findScopeHREF = (href) => {
+    let currentURL = new URL(href);
+    let protocol = currentURL.protocol;
+    // Non-opaque blobs adopt origins
+    if (protocol === 'blob:' && currentURL.origin !== 'null') {
+      currentURL = new URL(currentURL.origin);
+      protocol = currentURL.protocol;
+    }
+    // Only a few schemes are hierarchical
+    if (SPECIAL_SCHEMES.has(currentURL.protocol)) {
+      // Make first '..' act like '.'
+      if (currentURL.pathname.slice(-1) !== '/') {
+        currentURL.pathname += '/';
+      }
+      let lastHREF;
+      let currentHREF = currentURL.href;
+      do {
+        if (this.#scopeDependencies.has(currentHREF)) {
+          return currentHREF;
+        }
+        lastHREF = currentHREF;
+        currentURL = new URL('..', currentURL);
+        currentHREF = currentURL.href;
+      } while (lastHREF !== currentHREF);
+    }
+    if (this.#scopeDependencies.has(protocol)) {
+      return protocol;
     }
     return null;
   }
 
+  #createResolver = (resolve) => {
+    return {
+      resolve: (to, conditions) => resolve(`${to}`, conditions),
+      reaction: this.#reaction
+    };
+  }
+
+  /**
+   * @param {string} requester
+   */
+  getDependencyMapper(requester) {
+    const requesterHREF = `${requester}`;
+    const dependencies = this.#resourceDependencies;
+    if (dependencies.has(requesterHREF)) {
+      return this.#createResolver(
+        dependencies.get(requesterHREF) ||
+        (() => null)
+      );
+    }
+    const scopes = this.#scopeDependencies;
+    if (scopes.size !== 0) {
+      const scopeHREF = this.#findScopeHREF(requesterHREF);
+      if (typeof scopeHREF === 'string') {
+        return this.#createResolver(scopes.get(scopeHREF));
+      }
+    }
+    return this.#createResolver(() => null);
+  }
+
   assertIntegrity(url, content) {
     const href = `${url}`;
     debug('Checking integrity of %s', href);
-    const integrities = this.#integrities;
     const realIntegrities = new Map();
-
-    if (integrities.has(href)) {
+    const integrities = this.#resourceIntegrities;
+    function processEntry(href) {
       let integrityEntries = integrities.get(href);
       if (integrityEntries === true) return true;
       if (typeof integrityEntries === 'string') {
@@ -291,25 +480,54 @@ class Manifest {
         integrities.set(href, sri);
         integrityEntries = sri;
       }
-      // Avoid clobbered Symbol.iterator
-      for (let i = 0; i < integrityEntries.length; i++) {
-        const {
-          algorithm,
-          value: expected
-        } = integrityEntries[i];
-        const hash = createHash(algorithm);
-        HashUpdate(hash, content);
-        const digest = HashDigest(hash);
-        if (digest.length === expected.length &&
-          timingSafeEqual(digest, expected)) {
+      return integrityEntries;
+    }
+    if (integrities.has(href)) {
+      const integrityEntries = processEntry(href);
+      if (integrityEntries === true) return true;
+      if (ArrayIsArray(integrityEntries)) {
+        // Avoid clobbered Symbol.iterator
+        for (let i = 0; i < integrityEntries.length; i++) {
+          const {
+            algorithm,
+            value: expected
+          } = integrityEntries[i];
+          const hash = createHash(algorithm);
+          HashUpdate(hash, content);
+          const digest = HashDigest(hash);
+          if (digest.length === expected.length &&
+            timingSafeEqual(digest, expected)) {
+            return true;
+          }
+          MapPrototypeSet(
+            realIntegrities,
+            algorithm,
+            BufferToString(digest, 'base64')
+          );
+        }
+      }
+
+      if (integrityEntries !== kCascade) {
+        const error = new ERR_MANIFEST_ASSERT_INTEGRITY(url, realIntegrities);
+        this.#reaction(error);
+      }
+    }
+    let scope = this.#findScopeHREF(href);
+    while (scope !== null) {
+      if (this.#scopeIntegrities.has(scope)) {
+        const entry = this.#scopeIntegrities.get(scope);
+        if (entry === true) {
           return true;
+        } else if (entry === kCascade) {
+        } else {
+          break;
         }
-        MapPrototypeSet(
-          realIntegrities,
-          algorithm,
-          BufferToString(digest, 'base64')
-        );
       }
+      const nextScope = this.#findScopeHREF(new URL('..', scope));
+      if (!nextScope || nextScope === scope) {
+        break;
+      }
+      scope = nextScope;
     }
     const error = new ERR_MANIFEST_ASSERT_INTEGRITY(url, realIntegrities);
     this.#reaction(error);
diff --git a/lib/internal/process/execution.js b/lib/internal/process/execution.js
index c948552453306b..1087afadc5d659 100644
--- a/lib/internal/process/execution.js
+++ b/lib/internal/process/execution.js
@@ -1,9 +1,5 @@
 'use strict';
 
-const {
-  JSONStringify,
-} = primordials;
-
 const path = require('path');
 
 const {
@@ -59,44 +55,41 @@ function evalScript(name, body, breakFirstLine, print) {
   const { pathToFileURL } = require('url');
 
   const cwd = tryGetCwd();
-  const origModule = global.module;  // Set e.g. when called from the REPL.
+  const origModule = globalThis.module;  // Set e.g. when called from the REPL.
 
   const module = new CJSModule(name);
   module.filename = path.join(cwd, name);
   module.paths = CJSModule._nodeModulePaths(cwd);
 
-  global.kVmBreakFirstLineSymbol = kVmBreakFirstLineSymbol;
-  global.asyncESM = require('internal/process/esm_loader');
-
+  const asyncESM = require('internal/process/esm_loader');
   const baseUrl = pathToFileURL(module.filename).href;
 
+  // Create wrapper for cache entry
   const script = `
-    global.__filename = ${JSONStringify(name)};
-    global.exports = exports;
-    global.module = module;
-    global.__dirname = __dirname;
-    global.require = require;
-    const { kVmBreakFirstLineSymbol, asyncESM } = global;
-    delete global.kVmBreakFirstLineSymbol;
-    delete global.asyncESM;
-    return require("vm").runInThisContext(
-      ${JSONStringify(body)}, {
-        filename: ${JSONStringify(name)},
-        displayErrors: true,
-        [kVmBreakFirstLineSymbol]: ${!!breakFirstLine},
-        async importModuleDynamically (specifier) {
-          const loader = await asyncESM.ESMLoader;
-          return loader.import(specifier, ${JSONStringify(baseUrl)});
-        }
-      });\n`;
-  const result = module._compile(script, `${name}-wrapper`);
+    globalThis.module = module;
+    globalThis.exports = exports;
+    globalThis.__dirname = __dirname;
+    globalThis.require = require;
+    return (main) => main();
+  `;
+  globalThis.__filename = name;
+  const result = module._compile(script, `${name}-wrapper`)(() =>
+    require('vm').runInThisContext(body, {
+      filename: name,
+      displayErrors: true,
+      [kVmBreakFirstLineSymbol]: !!breakFirstLine,
+      async importModuleDynamically(specifier) {
+        const loader = await asyncESM.ESMLoader;
+        return loader.import(specifier, baseUrl);
+      }
+    }));
   if (print) {
     const { log } = require('internal/console/global');
     log(result);
   }
 
   if (origModule !== undefined)
-    global.module = origModule;
+    globalThis.module = origModule;
 }
 
 const exceptionHandlerState = { captureFn: null };
diff --git a/lib/internal/util/compositekey.js b/lib/internal/util/compositekey.js
deleted file mode 100644
index 9b7c460231f876..00000000000000
--- a/lib/internal/util/compositekey.js
+++ /dev/null
@@ -1,114 +0,0 @@
-'use strict';
-const {
-  codes: {
-    ERR_INVALID_ARG_VALUE,
-  },
-} = require('internal/errors');
-const {
-  ObjectCreate,
-  ObjectFreeze,
-  SafeMap,
-  SafeWeakMap,
-} = primordials;
-/**
- * @param {any} value
- * @returns {boolean}
- */
-const hasLifetime = (value) => {
-  return value !== null && (
-    typeof value === 'object' ||
-    typeof value === 'function'
-  );
-};
-class CompositeNode {
-  /**
-   * @type {WeakMap<object, Map<number, CompositeNode>>}
-   */
-  lifetimeNodes;
-  /**
-   * @type {Map<any, Map<number, CompositeNode>>}
-   */
-  primitiveNodes;
-  /**
-   * @type {null | Readonly<{}>}
-   */
-  value;
-  constructor() {
-    this.value = null;
-  }
-  get() {
-    if (this.value === null) {
-      return this.value = ObjectFreeze(ObjectCreate(null));
-    }
-    return this.value;
-  }
-  /**
-   * @param {any} value
-   * @param {number} position
-   */
-  emplacePrimitive(value, position) {
-    if (!this.primitiveNodes) {
-      this.primitiveNodes = new SafeMap();
-    }
-    if (!this.primitiveNodes.has(value)) {
-      this.primitiveNodes.set(value, new SafeMap());
-    }
-    const positions = this.primitiveNodes.get(value);
-    if (!positions.has(position)) {
-      positions.set(position, new CompositeNode());
-    }
-    return positions.get(position);
-  }
-  /**
-   * @param {object} value
-   * @param {number} position
-   */
-  emplaceLifetime(value, position) {
-    if (!this.lifetimeNodes) {
-      this.lifetimeNodes = new SafeWeakMap();
-    }
-    if (!this.lifetimeNodes.has(value)) {
-      this.lifetimeNodes.set(value, new SafeMap());
-    }
-    const positions = this.lifetimeNodes.get(value);
-    if (!positions.has(position)) {
-      positions.set(position, new CompositeNode());
-    }
-    return positions.get(position);
-  }
-}
-const compoundStore = new CompositeNode();
-// Accepts objects as a key and does identity on the parts of the iterable
-/**
- * @param {any[]} parts
- */
-const compositeKey = (parts) => {
-  /**
-   * @type {CompositeNode}
-   */
-  let node = compoundStore;
-  for (let i = 0; i < parts.length; i++) {
-    const value = parts[i];
-    if (hasLifetime(value)) {
-      node = node.emplaceLifetime(value, i);
-      parts[i] = hasLifetime;
-    }
-  }
-  // Does not leak WeakMap paths since there are none added
-  if (node === compoundStore) {
-    throw new ERR_INVALID_ARG_VALUE(
-      'parts',
-      parts,
-      'must contain a non-primitive element');
-  }
-  for (let i = 0; i < parts.length; i++) {
-    const value = parts[i];
-    if (value !== hasLifetime) {
-      node = node.emplacePrimitive(value, i);
-    }
-  }
-  return node.get();
-};
-module.exports = {
-  compositeKey
-};
diff --git a/node.gyp b/node.gyp
index 22c270123f1658..5da3ae61bcba14 100644
--- a/node.gyp
+++ b/node.gyp
@@ -215,7 +215,6 @@
       'lib/internal/url.js',
       'lib/internal/util.js',
       'lib/internal/util/comparisons.js',
-      'lib/internal/util/compositekey.js',
       'lib/internal/util/debuglog.js',
       'lib/internal/util/inspect.js',
       'lib/internal/util/inspector.js',
diff --git a/test/fixtures/policy/dependencies/dependencies-scopes-policy.json b/test/fixtures/policy/dependencies/dependencies-scopes-policy.json
new file mode 100644
index 00000000000000..2af78b0fa945bf
--- /dev/null
+++ b/test/fixtures/policy/dependencies/dependencies-scopes-policy.json
@@ -0,0 +1,8 @@
+{
+  "scopes": {
+    "../": {
+      "integrity": true,
+      "dependencies": true
+    }
+  }
+}
diff --git a/test/fixtures/policy/main.mjs b/test/fixtures/policy/main.mjs
new file mode 100644
index 00000000000000..feac7e3b8c946c
--- /dev/null
+++ b/test/fixtures/policy/main.mjs
@@ -0,0 +1,2 @@
+'use strict';
+export default 'main.mjs';
diff --git a/test/message/eval_messages.out b/test/message/eval_messages.out
index 64743d4ae67acf..4ba0d35974fc21 100644
--- a/test/message/eval_messages.out
+++ b/test/message/eval_messages.out
@@ -6,8 +6,8 @@ SyntaxError: Strict mode code may not include a with statement
     at new Script (vm.js:*:*)
     at createScript (vm.js:*:*)
     at Object.runInThisContext (vm.js:*:*)
-    at Object.<anonymous> ([eval]-wrapper:*:*)
-    at Module._compile (internal/modules/cjs/loader.js:*:*)
+    at internal/process/execution.js:*:*
+    at [eval]-wrapper:*:*
     at evalScript (internal/process/execution.js:*:*)
     at internal/main/eval_string.js:*:*
 42
@@ -20,8 +20,8 @@ Error: hello
     at [eval]:1:7
     at Script.runInThisContext (vm.js:*:*)
     at Object.runInThisContext (vm.js:*:*)
-    at Object.<anonymous> ([eval]-wrapper:*:*)
-    at Module._compile (internal/modules/cjs/loader.js:*:*)
+    at internal/process/execution.js:*:*
+    at [eval]-wrapper:*:*
     at evalScript (internal/process/execution.js:*:*)
     at internal/main/eval_string.js:*:*
 
@@ -33,8 +33,8 @@ Error: hello
     at [eval]:1:7
     at Script.runInThisContext (vm.js:*:*)
     at Object.runInThisContext (vm.js:*:*)
-    at Object.<anonymous> ([eval]-wrapper:*:*)
-    at Module._compile (internal/modules/cjs/loader.js:*:*)
+    at internal/process/execution.js:*:*
+    at [eval]-wrapper:*:*
     at evalScript (internal/process/execution.js:*:*)
     at internal/main/eval_string.js:*:*
 100
@@ -46,8 +46,8 @@ ReferenceError: y is not defined
     at [eval]:1:16
     at Script.runInThisContext (vm.js:*:*)
     at Object.runInThisContext (vm.js:*:*)
-    at Object.<anonymous> ([eval]-wrapper:*:*)
-    at Module._compile (internal/modules/cjs/loader.js:*:*)
+    at internal/process/execution.js:*:*
+    at [eval]-wrapper:*:*
     at evalScript (internal/process/execution.js:*:*)
     at internal/main/eval_string.js:*:*
 
diff --git a/test/message/stdin_messages.out b/test/message/stdin_messages.out
index 3c71c5683b7d94..3570047012c219 100644
--- a/test/message/stdin_messages.out
+++ b/test/message/stdin_messages.out
@@ -7,8 +7,8 @@ SyntaxError: Strict mode code may not include a with statement
     at new Script (vm.js:*)
     at createScript (vm.js:*)
     at Object.runInThisContext (vm.js:*)
-    at Object.<anonymous> ([stdin]-wrapper:*:*)
-    at Module._compile (internal/modules/cjs/loader.js:*:*)
+    at internal/process/execution.js:*:*
+    at [stdin]-wrapper:*:*
     at evalScript (internal/process/execution.js:*:*)
     at internal/main/eval_stdin.js:*:*
     at Socket.<anonymous> (internal/process/execution.js:*:*)
@@ -24,8 +24,8 @@ Error: hello
     at [stdin]:1:7
     at Script.runInThisContext (vm.js:*)
     at Object.runInThisContext (vm.js:*)
-    at Object.<anonymous> ([stdin]-wrapper:*:*)
-    at Module._compile (internal/modules/cjs/loader.js:*:*)
+    at internal/process/execution.js:*:*
+    at [stdin]-wrapper:*:*
     at evalScript (internal/process/execution.js:*:*)
     at internal/main/eval_stdin.js:*:*
     at Socket.<anonymous> (internal/process/execution.js:*:*)
@@ -39,8 +39,8 @@ Error: hello
     at [stdin]:1:*
     at Script.runInThisContext (vm.js:*)
     at Object.runInThisContext (vm.js:*)
-    at Object.<anonymous> ([stdin]-wrapper:*:*)
-    at Module._compile (internal/modules/cjs/loader.js:*:*)
+    at internal/process/execution.js:*:*
+    at [stdin]-wrapper:*:*
     at evalScript (internal/process/execution.js:*:*)
     at internal/main/eval_stdin.js:*:*
     at Socket.<anonymous> (internal/process/execution.js:*:*)
@@ -55,8 +55,8 @@ ReferenceError: y is not defined
     at [stdin]:1:16
     at Script.runInThisContext (vm.js:*)
     at Object.runInThisContext (vm.js:*)
-    at Object.<anonymous> ([stdin]-wrapper:*:*)
-    at Module._compile (internal/modules/cjs/loader.js:*:*)
+    at internal/process/execution.js:*:*
+    at [stdin]-wrapper:*:*
     at evalScript (internal/process/execution.js:*:*)
     at internal/main/eval_stdin.js:*:*
     at Socket.<anonymous> (internal/process/execution.js:*:*)
diff --git a/test/parallel/test-policy-dependency-conditions.js b/test/parallel/test-policy-dependency-conditions.js
index af865538ce7ebd..c9db95929daeec 100644
--- a/test/parallel/test-policy-dependency-conditions.js
+++ b/test/parallel/test-policy-dependency-conditions.js
@@ -84,7 +84,7 @@ for (const totalDepth of [1, 2, 3]) {
         }
       }
     });
-    const redirector = manifest.getRedirector('test:_');
+    const redirector = manifest.getDependencyMapper('test:_');
     for (const { target, conditions } of order) {
       const result = redirector.resolve('_', conditions).href;
       if (result !== target) {
diff --git a/test/parallel/test-policy-scopes-dependencies.js b/test/parallel/test-policy-scopes-dependencies.js
new file mode 100644
index 00000000000000..202e6459a6543e
--- /dev/null
+++ b/test/parallel/test-policy-scopes-dependencies.js
@@ -0,0 +1,306 @@
+'use strict';
+// Flags: --expose-internals
+
+const common = require('../common');
+
+if (!common.hasCrypto) common.skip('missing crypto');
+
+const Manifest = require('internal/policy/manifest').Manifest;
+const assert = require('assert');
+
+// #region files
+{
+  const baseURLs = [
+    // Localhost is special cased in spec
+    'file://localhost/root',
+    'file:///root',
+    'file:///',
+    'file:///root/dir1',
+    'file:///root/dir1/',
+    'file:///root/dir1/dir2',
+    'file:///root/dir1/dir2/'
+  ];
+
+  {
+    const manifest = new Manifest({
+      scopes: {
+        'file:///': {
+          dependencies: true
+        }
+      }
+    });
+
+    for (const href of baseURLs) {
+      assert.strictEqual(
+        manifest.getDependencyMapper(href).resolve('fs'),
+        true
+      );
+    }
+  }
+  {
+    const manifest = new Manifest({
+      scopes: {
+        'file:': {
+          dependencies: true
+        }
+      }
+    });
+
+    for (const href of baseURLs) {
+      assert.strictEqual(
+        manifest
+          .getDependencyMapper(href)
+          .resolve('fs'),
+        true);
+    }
+
+    assert.strictEqual(
+      manifest
+        .getDependencyMapper('file://host/')
+        .resolve('fs'),
+      true);
+  }
+  {
+    const manifest = new Manifest({
+      resources: {
+        'file:///root/dir1': {
+          dependencies: {
+            fs: 'test:fs1'
+          }
+        },
+        'file:///root/dir1/isolated': {},
+        'file:///root/dir1/cascade': {
+          cascade: true
+        }
+      },
+      scopes: {
+        'file:///root/dir1/': {
+          dependencies: {
+            fs: 'test:fs2'
+          }
+        },
+        'file:///root/dir1/censor/': {
+        },
+      }
+    });
+
+    for (const href of baseURLs) {
+      const redirector = manifest.getDependencyMapper(href);
+      if (href.startsWith('file:///root/dir1/')) {
+        assert.strictEqual(
+          redirector.resolve('fs').href,
+          'test:fs2'
+        );
+      } else if (href === 'file:///root/dir1') {
+        assert.strictEqual(
+          redirector.resolve('fs').href,
+          'test:fs1'
+        );
+      } else {
+        assert.strictEqual(redirector.resolve('fs'), null);
+      }
+    }
+
+    assert.strictEqual(
+      manifest
+        .getDependencyMapper('file:///root/dir1/isolated')
+        .resolve('fs'),
+      null
+    );
+    assert.strictEqual(
+      manifest
+        .getDependencyMapper('file:///root/dir1/cascade')
+        .resolve('fs').href,
+      'test:fs2'
+    );
+    assert.strictEqual(
+      manifest
+        .getDependencyMapper('file:///root/dir1/censor/foo')
+        .resolve('fs'),
+      null
+    );
+  }
+}
+// #endregion
+// #region data
+{
+  const baseURLs = [
+    'data:text/javascript,0',
+    'data:text/javascript,0/1',
+  ];
+
+  {
+    const manifest = new Manifest({
+      scopes: {
+        'data:text/': {
+          dependencies: {
+            fs: true
+          }
+        }
+      }
+    });
+
+    for (const href of baseURLs) {
+      assert.strictEqual(
+        manifest.getDependencyMapper(href).resolve('fs'),
+        null);
+    }
+  }
+  {
+    const manifest = new Manifest({
+      scopes: {
+        'data:/': {
+          dependencies: {
+            fs: true
+          }
+        }
+      }
+    });
+
+    for (const href of baseURLs) {
+      assert.strictEqual(
+        manifest.getDependencyMapper(href).resolve('fs'),
+        null);
+    }
+  }
+  {
+    const manifest = new Manifest({
+      scopes: {
+        'data:': {
+          dependencies: true
+        }
+      }
+    });
+
+    for (const href of baseURLs) {
+      assert.strictEqual(
+        manifest.getDependencyMapper(href).resolve('fs'),
+        true
+      );
+    }
+  }
+  {
+    const manifest = new Manifest({
+      scopes: {
+        'data:text/javascript,0/': {
+          dependencies: {
+            fs: 'test:fs1'
+          }
+        },
+      }
+    });
+
+    for (const href of baseURLs) {
+      assert.strictEqual(
+        manifest.getDependencyMapper(href).resolve('fs'),
+        null);
+    }
+  }
+}
+// #endregion
+// #region blob
+{
+  {
+    const manifest = new Manifest({
+      scopes: {
+        'https://example.com/': {
+          dependencies: true
+        }
+      }
+    });
+
+    assert.strictEqual(
+      manifest
+          .getDependencyMapper('blob:https://example.com/has-origin')
+          .resolve('fs'),
+      true
+    );
+  }
+  {
+    const manifest = new Manifest({
+      scopes: {
+        'https://example.com': {
+          dependencies: true
+        }
+      }
+    });
+
+    assert.strictEqual(
+      manifest
+          .getDependencyMapper('blob:https://example.com/has-origin')
+          .resolve('fs'),
+      true
+    );
+  }
+  {
+    const manifest = new Manifest({
+      scopes: {
+      }
+    });
+
+    assert.strictEqual(
+      manifest
+        .getDependencyMapper('blob:https://example.com/has-origin')
+        .resolve('fs'),
+      null);
+  }
+  {
+    const manifest = new Manifest({
+      scopes: {
+        'blob:https://example.com/has-origin': {
+          cascade: true
+        }
+      }
+    });
+
+    assert.strictEqual(
+      manifest
+        .getDependencyMapper('blob:https://example.com/has-origin')
+        .resolve('fs'),
+      null);
+  }
+  {
+    const manifest = new Manifest({
+      scopes: {
+        // FIXME
+        'https://example.com/': {
+          dependencies: true
+        },
+        'blob:https://example.com/has-origin': {
+          cascade: true
+        }
+      }
+    });
+
+    assert.strictEqual(
+      manifest
+        .getDependencyMapper('blob:https://example.com/has-origin')
+        .resolve('fs'),
+      true
+    );
+  }
+  {
+    const manifest = new Manifest({
+      scopes: {
+        'blob:': {
+          dependencies: true
+        },
+        'blob:https://example.com/has-origin': {
+          cascade: true
+        }
+      }
+    });
+
+    assert.strictEqual(
+      manifest
+        .getDependencyMapper('blob:https://example.com/has-origin')
+        .resolve('fs'),
+      null);
+    assert.strictEqual(
+      manifest
+        .getDependencyMapper('blob:foo').resolve('fs'),
+      true
+    );
+  }
+}
+// #endregion
diff --git a/test/parallel/test-policy-scopes-integrity.js b/test/parallel/test-policy-scopes-integrity.js
new file mode 100644
index 00000000000000..b506c92c41f625
--- /dev/null
+++ b/test/parallel/test-policy-scopes-integrity.js
@@ -0,0 +1,282 @@
+'use strict';
+// Flags: --expose-internals
+
+const common = require('../common');
+
+if (!common.hasCrypto) common.skip('missing crypto');
+
+const Manifest = require('internal/policy/manifest').Manifest;
+const assert = require('assert');
+
+// #region files
+{
+  const baseURLs = [
+    // Localhost is special cased in spec
+    'file://localhost/root',
+    'file:///root',
+    'file:///',
+    'file:///root/dir1',
+    'file:///root/dir1/',
+    'file:///root/dir1/dir2',
+    'file:///root/dir1/dir2/'
+  ];
+
+  {
+    const manifest = new Manifest({
+      scopes: {
+        'file:///': {
+          integrity: true
+        }
+      }
+    });
+
+    for (const href of baseURLs) {
+      assert.strictEqual(
+        manifest.assertIntegrity(href),
+        true
+      );
+      assert.strictEqual(
+        manifest.assertIntegrity(href, null),
+        true
+      );
+      assert.strictEqual(
+        manifest.assertIntegrity(href, ''),
+        true
+      );
+    }
+  }
+  {
+    const manifest = new Manifest({
+      scopes: {
+        'file:': {
+          integrity: true
+        }
+      }
+    });
+
+    for (const href of baseURLs) {
+      assert.strictEqual(
+        manifest.assertIntegrity(href),
+        true
+      );
+      assert.strictEqual(
+        manifest.assertIntegrity(href, null),
+        true
+      );
+      assert.strictEqual(
+        manifest.assertIntegrity(href, ''),
+        true
+      );
+    }
+  }
+  {
+    const manifest = new Manifest({
+      resources: {
+        'file:///root/dir1/isolated': {},
+        'file:///root/dir1/cascade': {
+          cascade: true
+        }
+      },
+      scopes: {
+        'file:///root/dir1/': {
+          integrity: true,
+        },
+        'file:///root/dir1/dir2/': {
+          cascade: true,
+        },
+        'file:///root/dir1/censor/': {
+        },
+      }
+    });
+    assert.throws(
+      () => {
+        manifest.assertIntegrity('file:///root/dir1/isolated');
+      },
+      /ERR_MANIFEST_ASSERT_INTEGRITY/
+    );
+    assert.strictEqual(
+      manifest.assertIntegrity('file:///root/dir1/cascade'),
+      true
+    );
+    assert.strictEqual(
+      manifest.assertIntegrity('file:///root/dir1/enoent'),
+      true
+    );
+    assert.strictEqual(
+      manifest.assertIntegrity('file:///root/dir1/dir2/enoent'),
+      true
+    );
+    assert.throws(
+      () => {
+        manifest.assertIntegrity('file:///root/dir1/censor/enoent');
+      },
+      /ERR_MANIFEST_ASSERT_INTEGRITY/
+    );
+  }
+}
+// #endregion
+// #region data
+{
+  const baseURLs = [
+    'data:text/javascript,0',
+    'data:text/javascript,0/1',
+  ];
+
+  {
+    const manifest = new Manifest({
+      scopes: {
+        'data:text/': {
+          integrity: true
+        }
+      }
+    });
+
+    for (const href of baseURLs) {
+      assert.throws(
+        () => {
+          manifest.assertIntegrity(href);
+        },
+        /ERR_MANIFEST_ASSERT_INTEGRITY/
+      );
+    }
+  }
+  {
+    const manifest = new Manifest({
+      scopes: {
+        'data:/': {
+          integrity: true
+        }
+      }
+    });
+
+    for (const href of baseURLs) {
+      assert.throws(
+        () => {
+          manifest.assertIntegrity(href);
+        },
+        /ERR_MANIFEST_ASSERT_INTEGRITY/
+      );
+    }
+  }
+  {
+    const manifest = new Manifest({
+      scopes: {
+        'data:': {
+          integrity: true
+        }
+      }
+    });
+
+    for (const href of baseURLs) {
+      assert.strictEqual(manifest.assertIntegrity(href), true);
+    }
+  }
+  {
+    const manifest = new Manifest({
+      scopes: {
+        'data:text/javascript,0/': {
+          integrity: true
+        },
+      }
+    });
+
+    for (const href of baseURLs) {
+      assert.throws(
+        () => {
+          manifest.assertIntegrity(href);
+        },
+        /ERR_MANIFEST_ASSERT_INTEGRITY/
+      );
+    }
+  }
+}
+// #endregion
+// #region blob
+{
+  {
+    const manifest = new Manifest({
+      scopes: {
+        'https://example.com/': {
+          integrity: true
+        }
+      }
+    });
+
+    assert.strictEqual(
+      manifest.assertIntegrity('blob:https://example.com/has-origin'),
+      true
+    );
+  }
+  {
+    const manifest = new Manifest({
+      scopes: {
+      }
+    });
+
+    assert.throws(
+      () => {
+        manifest.assertIntegrity('blob:https://example.com/has-origin');
+      },
+      /ERR_MANIFEST_ASSERT_INTEGRITY/
+    );
+  }
+  {
+    const manifest = new Manifest({
+      scopes: {
+        'blob:https://example.com/has-origin': {
+          cascade: true
+        }
+      }
+    });
+
+    assert.throws(
+      () => {
+        manifest.assertIntegrity('blob:https://example.com/has-origin');
+      },
+      /ERR_MANIFEST_ASSERT_INTEGRITY/
+    );
+  }
+  {
+    const manifest = new Manifest({
+      resources: {
+        'blob:https://example.com/has-origin': {
+          cascade: true
+        }
+      },
+      scopes: {
+        'https://example.com': {
+          integrity: true
+        }
+      }
+    });
+
+    assert.strictEqual(
+      manifest.assertIntegrity('blob:https://example.com/has-origin'),
+      true
+    );
+  }
+  {
+    const manifest = new Manifest({
+      scopes: {
+        'blob:': {
+          integrity: true
+        },
+        'https://example.com': {
+          cascade: true
+        }
+      }
+    });
+
+    assert.throws(
+      () => {
+        manifest.assertIntegrity('blob:https://example.com/has-origin');
+      },
+      /ERR_MANIFEST_ASSERT_INTEGRITY/
+    );
+    assert.strictEqual(
+      manifest.assertIntegrity('blob:foo'),
+      true
+    );
+  }
+}
+// #endregion
diff --git a/test/parallel/test-policy-scopes.js b/test/parallel/test-policy-scopes.js
new file mode 100644
index 00000000000000..b1ba160bdde3f1
--- /dev/null
+++ b/test/parallel/test-policy-scopes.js
@@ -0,0 +1,25 @@
+'use strict';
+
+const common = require('../common');
+if (!common.hasCrypto)
+  common.skip('missing crypto');
+
+const fixtures = require('../common/fixtures');
+
+const assert = require('assert');
+const { spawnSync } = require('child_process');
+
+const dep = fixtures.path('policy', 'main.mjs');
+{
+  const depPolicy = fixtures.path(
+    'policy',
+    'dependencies',
+    'dependencies-scopes-policy.json');
+  const { status } = spawnSync(
+    process.execPath,
+    [
+      '--experimental-policy', depPolicy, dep,
+    ]
+  );
+  assert.strictEqual(status, 0);
+}
diff --git a/test/sequential/test-inspector-async-hook-setup-at-inspect-brk.js b/test/sequential/test-inspector-async-hook-setup-at-inspect-brk.js
index f4f45a1aa8f4ce..053108c415980f 100644
--- a/test/sequential/test-inspector-async-hook-setup-at-inspect-brk.js
+++ b/test/sequential/test-inspector-async-hook-setup-at-inspect-brk.js
@@ -24,7 +24,7 @@ async function checkAsyncStackTrace(session) {
          `${Object.keys(paused.params)} contains "asyncStackTrace" property`);
   assert(paused.params.asyncStackTrace.description, 'Timeout');
   assert(paused.params.asyncStackTrace.callFrames
-           .some((frame) => frame.functionName === 'Module._compile'));
+           .some((frame) => frame.url === 'internal/process/execution.js'));
 }
 
 async function runTests() {
diff --git a/test/sequential/test-inspector-async-stack-traces-set-interval.js b/test/sequential/test-inspector-async-stack-traces-set-interval.js
index 97b2917b70092c..8f884614cc7d95 100644
--- a/test/sequential/test-inspector-async-stack-traces-set-interval.js
+++ b/test/sequential/test-inspector-async-stack-traces-set-interval.js
@@ -20,7 +20,7 @@ async function checkAsyncStackTrace(session) {
          `${Object.keys(paused.params)} contains "asyncStackTrace" property`);
   assert(paused.params.asyncStackTrace.description, 'Timeout');
   assert(paused.params.asyncStackTrace.callFrames
-           .some((frame) => frame.functionName === 'Module._compile'));
+           .some((frame) => frame.url === 'internal/process/execution.js'));
 }
 
 async function runTests() {