[DIP] Implement CORP checks on subresources

This CL implements the CORP checks on subresources for documents using

Document-Isolation-Policy: isolate-and-require-corp and
Document-Isolation-Policy: isolate-and-credentialless. In the later
case, this check only applies to credentialled subresources.

A follow-up CL
(https://chromium-review.googlesource.com/c/chromium/src/+/5593879) will
implement proper error messaging in DevTools.

Bug: 333029144
Change-Id: I54812987b06187bbc69ee99f7fed88e5ce0b6713
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5537963
Reviewed-by: Tsuyoshi Horo <horo@chromium.org>
Reviewed-by: Joe DeBlasio <jdeblasio@chromium.org>
Reviewed-by: Mike West <mkwst@chromium.org>
Reviewed-by: Alex Rudenko <alexrudenko@chromium.org>
Reviewed-by: Mason Freed <masonf@chromium.org>
Commit-Queue: Camille Lamy <clamy@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1309953}
diff --git a/content/browser/cache_storage/cache_storage_dispatcher_host.cc b/content/browser/cache_storage/cache_storage_dispatcher_host.cc
index e0e1348..905489d02d 100644
--- a/content/browser/cache_storage/cache_storage_dispatcher_host.cc
+++ b/content/browser/cache_storage/cache_storage_dispatcher_host.cc
@@ -155,12 +155,15 @@
   if (corp_header != response->headers.end())
     corp_header_value = corp_header->second;
 
+  // TODO(https://issues.chromium.org/issues/333029144):
+  // Pass the appropriate DocumentIsolationPolicy for the context.
   return CrossOriginResourcePolicy::IsBlockedByHeaderValue(
              response->url_list.back(), response->url_list.front(),
              document_origin, corp_header_value, RequestMode::kNoCors,
              network::mojom::RequestDestination::kEmpty,
              response->request_include_credentials, document_coep,
-             coep_reporter ? coep_reporter.get() : nullptr)
+             coep_reporter ? coep_reporter.get() : nullptr,
+             network::DocumentIsolationPolicy())
       .has_value();
 }
 
diff --git a/content/browser/devtools/devtools_instrumentation.cc b/content/browser/devtools/devtools_instrumentation.cc
index c3e874d..1a021b9 100644
--- a/content/browser/devtools/devtools_instrumentation.cc
+++ b/content/browser/devtools/devtools_instrumentation.cc
@@ -750,6 +750,9 @@
 
 protocol::String BuildBlockedByResponseReason(
     network::mojom::BlockedByResponseReason reason) {
+  // TODO(crbug.com/336752983):
+  // Add specific error messages when a subresource load was blocked due to
+  // Document-Isolation-Policy (Dip).
   switch (reason) {
     case network::mojom::BlockedByResponseReason::
         kCoepFrameResourceNeedsCoepHeader:
@@ -763,6 +766,10 @@
       return protocol::Audits::BlockedByResponseReasonEnum::CorpNotSameOrigin;
     case network::mojom::BlockedByResponseReason::
         kCorpNotSameOriginAfterDefaultedToSameOriginByCoep:
+    case network::mojom::BlockedByResponseReason::
+        kCorpNotSameOriginAfterDefaultedToSameOriginByDip:
+    case network::mojom::BlockedByResponseReason::
+        kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip:
       return protocol::Audits::BlockedByResponseReasonEnum::
           CorpNotSameOriginAfterDefaultedToSameOriginByCoep;
     case network::mojom::BlockedByResponseReason::kCorpNotSameSite:
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc
index 2df1eadd..24143d6a 100644
--- a/content/browser/devtools/protocol/network_handler.cc
+++ b/content/browser/devtools/protocol/network_handler.cc
@@ -2203,6 +2203,14 @@
         kCorpNotSameOriginAfterDefaultedToSameOriginByCoep:
       return protocol::Network::BlockedReasonEnum::
           CorpNotSameOriginAfterDefaultedToSameOriginByCoep;
+    case blink::ResourceRequestBlockedReason::
+        kCorpNotSameOriginAfterDefaultedToSameOriginByDip:
+      return protocol::Network::BlockedReasonEnum::
+          CorpNotSameOriginAfterDefaultedToSameOriginByDip;
+    case blink::ResourceRequestBlockedReason::
+        kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip:
+      return protocol::Network::BlockedReasonEnum::
+          CorpNotSameOriginAfterDefaultedToSameOriginByCoep;
     case blink::ResourceRequestBlockedReason::kCorpNotSameSite:
       return protocol::Network::BlockedReasonEnum::CorpNotSameSite;
     case blink::ResourceRequestBlockedReason::kConversionRequest:
@@ -2233,6 +2241,14 @@
           kCorpNotSameOriginAfterDefaultedToSameOriginByCoep:
         return {protocol::Network::BlockedReasonEnum::
                     CorpNotSameOriginAfterDefaultedToSameOriginByCoep};
+      case network::mojom::BlockedByResponseReason::
+          kCorpNotSameOriginAfterDefaultedToSameOriginByDip:
+        return {protocol::Network::BlockedReasonEnum::
+                    CorpNotSameOriginAfterDefaultedToSameOriginByDip};
+      case network::mojom::BlockedByResponseReason::
+          kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip:
+        return {protocol::Network::BlockedReasonEnum::
+                    CorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip};
       case network::mojom::BlockedByResponseReason::kCorpNotSameOrigin:
         return {protocol::Network::BlockedReasonEnum::CorpNotSameOrigin};
       case network::mojom::BlockedByResponseReason::kCorpNotSameSite:
diff --git a/content/browser/interest_group/interest_group_auction_reporter_unittest.cc b/content/browser/interest_group/interest_group_auction_reporter_unittest.cc
index 432a203..ede5054 100644
--- a/content/browser/interest_group/interest_group_auction_reporter_unittest.cc
+++ b/content/browser/interest_group/interest_group_auction_reporter_unittest.cc
@@ -671,7 +671,8 @@
           /*is_web_secure_context=*/true,
           /*ip_address_space=*/network::mojom::IPAddressSpace::kPublic,
           /*is_web_secure_context=*/
-          network::mojom::PrivateNetworkRequestPolicy::kBlock)};
+          network::mojom::PrivateNetworkRequestPolicy::kBlock,
+          network::DocumentIsolationPolicy())};
 
   const GURL kSellerReportUrl =
       GURL("https://seller.report.test/seller-report");
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index d57ed03..3525873 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -9287,7 +9287,8 @@
 
   return network::mojom::ClientSecurityState::New(
       policies.cross_origin_embedder_policy, policies.is_web_secure_context,
-      policies.ip_address_space, private_network_request_policy_);
+      policies.ip_address_space, private_network_request_policy_,
+      policies.document_isolation_policy);
 }
 
 std::string NavigationRequest::GetUserAgentOverride() {
diff --git a/content/browser/renderer_host/private_network_access_util.cc b/content/browser/renderer_host/private_network_access_util.cc
index 69abce5..888d8be 100644
--- a/content/browser/renderer_host/private_network_access_util.cc
+++ b/content/browser/renderer_host/private_network_access_util.cc
@@ -179,7 +179,8 @@
       policies.cross_origin_embedder_policy, policies.is_web_secure_context,
       policies.ip_address_space,
       DerivePrivateNetworkRequestPolicy(policies,
-                                        private_network_request_context));
+                                        private_network_request_context),
+      policies.document_isolation_policy);
 }
 
 // Special chrome schemes cannot directly be categorized in public/private/local
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index a856842..3e4e84d 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -13148,18 +13148,22 @@
     // Omitted: reporting endpoint, report-only value and reporting endpoint.
     network::CrossOriginEmbedderPolicy coep;
     coep.value = network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp;
+    network::DocumentIsolationPolicy dip;
+    dip.value =
+        network::mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp;
 
     return network::mojom::ClientSecurityState::New(
         std::move(coep),
         /*is_web_secure_context=*/false,
         network::mojom::IPAddressSpace::kUnknown,
-        network::mojom::PrivateNetworkRequestPolicy::kBlock);
+        network::mojom::PrivateNetworkRequestPolicy::kBlock, std::move(dip));
   }
 
   const PolicyContainerPolicies& policies = policy_container_host_->policies();
   return network::mojom::ClientSecurityState::New(
       policies.cross_origin_embedder_policy, policies.is_web_secure_context,
-      policies.ip_address_space, private_network_request_policy_);
+      policies.ip_address_space, private_network_request_policy_,
+      policies.document_isolation_policy);
 }
 
 network::mojom::ClientSecurityStatePtr
diff --git a/content/browser/service_worker/service_worker_register_job.cc b/content/browser/service_worker/service_worker_register_job.cc
index 17bfa7e..7918618 100644
--- a/content/browser/service_worker/service_worker_register_job.cc
+++ b/content/browser/service_worker/service_worker_register_job.cc
@@ -509,7 +509,8 @@
               creator_policy_container_policies_.ip_address_space,
               DerivePrivateNetworkRequestPolicy(
                   creator_policy_container_policies_,
-                  PrivateNetworkRequestContext::kWorker)));
+                  PrivateNetworkRequestContext::kWorker),
+              creator_policy_container_policies_.document_isolation_policy));
 
   new_script_fetcher_ = std::make_unique<ServiceWorkerNewScriptFetcher>(
       *context_, version, std::move(loader_factory),
@@ -613,7 +614,8 @@
               creator_policy_container_policies_.ip_address_space,
               DerivePrivateNetworkRequestPolicy(
                   creator_policy_container_policies_,
-                  PrivateNetworkRequestContext::kWorker)));
+                  PrivateNetworkRequestContext::kWorker),
+              creator_policy_container_policies_.document_isolation_policy));
   if (!loader_factory) {
     // We can't continue with update checking appropriately without
     // |loader_factory|. Null |loader_factory| means that the storage partition
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index d4577d4..cca2bea9 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -2076,7 +2076,8 @@
       policies.ip_address_space,
       DerivePrivateNetworkRequestPolicy(policies.ip_address_space,
                                         policies.is_web_secure_context,
-                                        PrivateNetworkRequestContext::kWorker));
+                                        PrivateNetworkRequestContext::kWorker),
+      policies.document_isolation_policy);
 }
 
 // static
diff --git a/content/browser/url_loader_factory_params_helper.cc b/content/browser/url_loader_factory_params_helper.cc
index 9c3e477d..6c54c2e3 100644
--- a/content/browser/url_loader_factory_params_helper.cc
+++ b/content/browser/url_loader_factory_params_helper.cc
@@ -324,12 +324,16 @@
       /*top_frame_origin=*/tentative_origin, /*frame_origin=*/tentative_origin,
       net::SiteForCookies::FromOrigin(tentative_origin));
 
+  // TODO(https://issues.chromium.org/issues/336754077):
+  // Support Document-Isolation-Policy in early hints headers instead of passing
+  // a default DocumentIsolationPolicy.
   network::mojom::ClientSecurityStatePtr client_security_state =
       network::mojom::ClientSecurityState::New(
           early_hints.headers->cross_origin_embedder_policy,
           network::IsOriginPotentiallyTrustworthy(tentative_origin),
           early_hints.ip_address_space,
-          network::mojom::PrivateNetworkRequestPolicy::kBlock);
+          network::mojom::PrivateNetworkRequestPolicy::kBlock,
+          network::DocumentIsolationPolicy());
 
   return CreateParams(
       process, /*origin=*/tentative_origin,
diff --git a/content/browser/worker_host/shared_worker_host.cc b/content/browser/worker_host/shared_worker_host.cc
index e3eee99a..e22ca62 100644
--- a/content/browser/worker_host/shared_worker_host.cc
+++ b/content/browser/worker_host/shared_worker_host.cc
@@ -44,6 +44,7 @@
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
 #include "services/network/public/cpp/cross_origin_embedder_policy.h"
+#include "services/network/public/cpp/document_isolation_policy.h"
 #include "services/network/public/cpp/is_potentially_trustworthy.h"
 #include "services/network/public/mojom/client_security_state.mojom-shared.h"
 #include "services/network/public/mojom/ip_address_space.mojom-shared.h"
@@ -239,7 +240,10 @@
           network::CrossOriginEmbedderPolicy(
               network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp),
           /*is_web_secure_context=*/false,
-          network::mojom::IPAddressSpace::kUnknown, policy);
+          network::mojom::IPAddressSpace::kUnknown, policy,
+          network::DocumentIsolationPolicy(
+              network::mojom::DocumentIsolationPolicyValue::
+                  kIsolateAndRequireCorp));
     }
 
     policy_container_host = std::move(creator_policy_container_host_);
diff --git a/services/network/network_service_memory_cache.cc b/services/network/network_service_memory_cache.cc
index 290ec52..6e60118b 100644
--- a/services/network/network_service_memory_cache.cc
+++ b/services/network/network_service_memory_cache.cc
@@ -31,6 +31,7 @@
 #include "services/network/network_service_memory_cache_writer.h"
 #include "services/network/private_network_access_checker.h"
 #include "services/network/public/cpp/cross_origin_resource_policy.h"
+#include "services/network/public/cpp/document_isolation_policy.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/orb/orb_api.h"
 #include "services/network/public/cpp/private_network_access_check_result.h"
@@ -453,12 +454,17 @@
 
   const mojom::URLResponseHeadPtr& response = it->second->response_head;
 
+  DocumentIsolationPolicy document_isolation_policy;
+  if (factory_client_security_state) {
+    document_isolation_policy =
+        factory_client_security_state->document_isolation_policy;
+  }
   std::optional<mojom::BlockedByResponseReason> blocked_reason =
       CrossOriginResourcePolicy::IsBlocked(
           /*request_url=*/url, /*original_url=*/url,
           resource_request.request_initiator, *response, resource_request.mode,
           resource_request.destination, cross_origin_embedder_policy,
-          /*reporter=*/nullptr);
+          /*reporter=*/nullptr, document_isolation_policy);
   if (blocked_reason.has_value())
     return std::nullopt;
 
diff --git a/services/network/public/cpp/cross_origin_resource_policy.cc b/services/network/public/cpp/cross_origin_resource_policy.cc
index c0af585..9ce952b 100644
--- a/services/network/public/cpp/cross_origin_resource_policy.cc
+++ b/services/network/public/cpp/cross_origin_resource_policy.cc
@@ -9,9 +9,11 @@
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/http/http_response_headers.h"
 #include "services/network/public/cpp/cross_origin_embedder_policy.h"
+#include "services/network/public/cpp/document_isolation_policy.h"
 #include "services/network/public/cpp/initiator_lock_compatibility.h"
 #include "services/network/public/cpp/url_loader_completion_status.h"
 #include "services/network/public/mojom/cross_origin_embedder_policy.mojom.h"
+#include "services/network/public/mojom/document_isolation_policy.mojom-forward.h"
 #include "services/network/public/mojom/url_response_head.mojom.h"
 #include "url/gurl.h"
 #include "url/origin.h"
@@ -109,35 +111,55 @@
     const std::optional<url::Origin>& request_initiator,
     mojom::RequestMode request_mode,
     bool request_include_credentials,
-    mojom::CrossOriginEmbedderPolicyValue embedder_policy) {
+    mojom::CrossOriginEmbedderPolicyValue embedder_policy,
+    mojom::DocumentIsolationPolicyValue document_isolation_policy) {
   // Browser-initiated requests are not subject to Cross-Origin-Resource-Policy.
   if (!request_initiator.has_value())
     return std::nullopt;
   const url::Origin& initiator = request_initiator.value();
 
-  bool require_corp;
+  bool require_corp_due_to_coep;
   switch (embedder_policy) {
     case mojom::CrossOriginEmbedderPolicyValue::kNone:
-      require_corp = false;
+      require_corp_due_to_coep = false;
       break;
 
     case mojom::CrossOriginEmbedderPolicyValue::kCredentialless:
-      require_corp = request_mode == mojom::RequestMode::kNavigate ||
-                     request_include_credentials;
+      require_corp_due_to_coep =
+          request_mode == mojom::RequestMode::kNavigate ||
+          request_include_credentials;
       break;
 
     case mojom::CrossOriginEmbedderPolicyValue::kRequireCorp:
-      require_corp = true;
+      require_corp_due_to_coep = true;
+      break;
+  }
+
+  bool require_corp_due_to_dip;
+  switch (document_isolation_policy) {
+    case mojom::DocumentIsolationPolicyValue::kNone:
+      require_corp_due_to_dip = false;
+      break;
+
+    case mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless:
+      require_corp_due_to_dip = request_mode == mojom::RequestMode::kNavigate ||
+                                request_include_credentials;
+      break;
+
+    case mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp:
+      require_corp_due_to_dip = true;
       break;
   }
 
   // COEP https://mikewest.github.io/corpp/#corp-check
-  bool upgrade_to_same_origin = false;
+  bool upgrade_to_same_origin_due_to_coep = false;
+  bool upgrade_to_same_origin_due_to_dip = false;
   if ((policy == CrossOriginResourcePolicy::kNoHeader ||
        policy == CrossOriginResourcePolicy::kParsingError) &&
-      require_corp) {
+      (require_corp_due_to_coep || require_corp_due_to_dip)) {
     policy = CrossOriginResourcePolicy::kSameOrigin;
-    upgrade_to_same_origin = true;
+    upgrade_to_same_origin_due_to_coep = require_corp_due_to_coep;
+    upgrade_to_same_origin_due_to_dip = require_corp_due_to_dip;
   }
 
   if (policy == CrossOriginResourcePolicy::kNoHeader ||
@@ -162,10 +184,22 @@
   // From https://fetch.spec.whatwg.org/#cross-origin-resource-policy-header:
   // > 4. If policy is `same-origin`, then return blocked.
   if (policy == CrossOriginResourcePolicy::kSameOrigin) {
-    return upgrade_to_same_origin
-               ? mojom::BlockedByResponseReason::
-                     kCorpNotSameOriginAfterDefaultedToSameOriginByCoep
-               : mojom::BlockedByResponseReason::kCorpNotSameOrigin;
+    if (upgrade_to_same_origin_due_to_coep &&
+        upgrade_to_same_origin_due_to_dip) {
+      return mojom::BlockedByResponseReason::
+          kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip;
+    }
+
+    if (upgrade_to_same_origin_due_to_coep) {
+      return mojom::BlockedByResponseReason::
+          kCorpNotSameOriginAfterDefaultedToSameOriginByCoep;
+    }
+
+    if (upgrade_to_same_origin_due_to_dip) {
+      return mojom::BlockedByResponseReason::
+          kCorpNotSameOriginAfterDefaultedToSameOriginByDip;
+    }
+    return mojom::BlockedByResponseReason::kCorpNotSameOrigin;
   }
 
   // From https://fetch.spec.whatwg.org/#cross-origin-resource-policy-header:
@@ -193,9 +227,12 @@
     mojom::RequestDestination request_destination,
     bool request_include_credentials,
     const CrossOriginEmbedderPolicy& embedder_policy,
-    mojom::CrossOriginEmbedderPolicyReporter* reporter) {
+    mojom::CrossOriginEmbedderPolicyReporter* reporter,
+    const DocumentIsolationPolicy& document_isolation_policy) {
   constexpr auto kBlockedDueToCoep = mojom::BlockedByResponseReason::
       kCorpNotSameOriginAfterDefaultedToSameOriginByCoep;
+  constexpr auto kBlockedDueToCoepAndDip = mojom::BlockedByResponseReason::
+      kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip;
   if ((embedder_policy.report_only_value ==
            mojom::CrossOriginEmbedderPolicyValue::kRequireCorp ||
        (embedder_policy.report_only_value ==
@@ -204,12 +241,17 @@
       reporter) {
     const auto result = IsBlockedInternal(
         policy, request_url, request_initiator, request_mode,
-        request_include_credentials, embedder_policy.report_only_value);
-    if (result == kBlockedDueToCoep ||
+        request_include_credentials, embedder_policy.report_only_value,
+        document_isolation_policy.report_only_value);
+    if (result == kBlockedDueToCoep || result == kBlockedDueToCoepAndDip ||
         (result.has_value() && request_mode == mojom::RequestMode::kNavigate)) {
       reporter->QueueCorpViolationReport(original_url, request_destination,
                                          /*report_only=*/true);
     }
+
+    // TODO(https://issues.chromium.org/issues/333029815)
+    // Emit a report when Document-Isolation-Policy enforcement would block
+    // subresource load.
   }
 
   if (request_mode == mojom::RequestMode::kNavigate &&
@@ -219,13 +261,18 @@
 
   const auto result =
       IsBlockedInternal(policy, request_url, request_initiator, request_mode,
-                        request_include_credentials, embedder_policy.value);
+                        request_include_credentials, embedder_policy.value,
+                        document_isolation_policy.value);
   if (reporter &&
-      (result == kBlockedDueToCoep ||
+      (result == kBlockedDueToCoep || result == kBlockedDueToCoepAndDip ||
        (result.has_value() && request_mode == mojom::RequestMode::kNavigate))) {
     reporter->QueueCorpViolationReport(original_url, request_destination,
                                        /*report_only=*/false);
   }
+
+  // TODO(https://issues.chromium.org/issues/333029815)
+  // Emit a report when Document-Isolation-Policy enforcement blocks
+  // subresource load.
   return result;
 }
 
@@ -245,7 +292,8 @@
     mojom::RequestMode request_mode,
     mojom::RequestDestination request_destination,
     const CrossOriginEmbedderPolicy& embedder_policy,
-    mojom::CrossOriginEmbedderPolicyReporter* reporter) {
+    mojom::CrossOriginEmbedderPolicyReporter* reporter,
+    const DocumentIsolationPolicy& document_isolation_policy) {
   // From https://fetch.spec.whatwg.org/#cross-origin-resource-policy-header:
   // > 1. If request’s mode is not "no-cors", then return allowed.
   if (request_mode != mojom::RequestMode::kNoCors)
@@ -264,7 +312,7 @@
   return IsBlockedInternalWithReporting(
       policy, request_url, original_url, request_initiator, request_mode,
       request_destination, response.request_include_credentials,
-      embedder_policy, reporter);
+      embedder_policy, reporter, document_isolation_policy);
 }
 
 // static
@@ -278,7 +326,8 @@
     mojom::RequestDestination request_destination,
     bool request_include_credentials,
     const CrossOriginEmbedderPolicy& embedder_policy,
-    mojom::CrossOriginEmbedderPolicyReporter* reporter) {
+    mojom::CrossOriginEmbedderPolicyReporter* reporter,
+    const DocumentIsolationPolicy& document_isolation_policy) {
   // From https://fetch.spec.whatwg.org/#cross-origin-resource-policy-header:
   // > 1. If request’s mode is not "no-cors", then return allowed.
   if (request_mode != mojom::RequestMode::kNoCors)
@@ -289,7 +338,7 @@
   return IsBlockedInternalWithReporting(
       policy, request_url, original_url, request_initiator, request_mode,
       request_destination, request_include_credentials, embedder_policy,
-      reporter);
+      reporter, document_isolation_policy);
 }
 
 // static
@@ -308,7 +357,8 @@
   return IsBlockedInternalWithReporting(
       policy, request_url, original_url, request_initiator,
       mojom::RequestMode::kNavigate, request_destination,
-      response.request_include_credentials, embedder_policy, reporter);
+      response.request_include_credentials, embedder_policy, reporter,
+      DocumentIsolationPolicy());
 }
 
 // static
diff --git a/services/network/public/cpp/cross_origin_resource_policy.h b/services/network/public/cpp/cross_origin_resource_policy.h
index e9539a35..e967582 100644
--- a/services/network/public/cpp/cross_origin_resource_policy.h
+++ b/services/network/public/cpp/cross_origin_resource_policy.h
@@ -23,6 +23,7 @@
 namespace network {
 
 struct CrossOriginEmbedderPolicy;
+struct DocumentIsolationPolicy;
 
 // Implementation of Cross-Origin-Resource-Policy - see:
 // - https://fetch.spec.whatwg.org/#cross-origin-resource-policy-header
@@ -52,20 +53,23 @@
       mojom::RequestMode request_mode,
       mojom::RequestDestination request_destination,
       const CrossOriginEmbedderPolicy& embedder_policy,
-      mojom::CrossOriginEmbedderPolicyReporter* reporter);
+      mojom::CrossOriginEmbedderPolicyReporter* reporter,
+      const DocumentIsolationPolicy& document_isolation_policy);
 
   // Same as IsBlocked(), but this method can take a raw value of
   // Cross-Origin-Resource-Policy header instead of using a URLResponseHead.
   [[nodiscard]] static std::optional<mojom::BlockedByResponseReason>
-  IsBlockedByHeaderValue(const GURL& request_url,
-                         const GURL& original_url,
-                         const std::optional<url::Origin>& request_initiator,
-                         std::optional<std::string> corp_header_value,
-                         mojom::RequestMode request_mode,
-                         mojom::RequestDestination request_destination,
-                         bool request_include_credentials,
-                         const CrossOriginEmbedderPolicy& embedder_policy,
-                         mojom::CrossOriginEmbedderPolicyReporter* reporter);
+  IsBlockedByHeaderValue(
+      const GURL& request_url,
+      const GURL& original_url,
+      const std::optional<url::Origin>& request_initiator,
+      std::optional<std::string> corp_header_value,
+      mojom::RequestMode request_mode,
+      mojom::RequestDestination request_destination,
+      bool request_include_credentials,
+      const CrossOriginEmbedderPolicy& embedder_policy,
+      mojom::CrossOriginEmbedderPolicyReporter* reporter,
+      const DocumentIsolationPolicy& document_isolation_policy);
 
   // The CORP check for navigation requests. This is expected to be called
   // from the navigation algorithm.
diff --git a/services/network/public/cpp/cross_origin_resource_policy_unittest.cc b/services/network/public/cpp/cross_origin_resource_policy_unittest.cc
index 23e1659..68b32b9 100644
--- a/services/network/public/cpp/cross_origin_resource_policy_unittest.cc
+++ b/services/network/public/cpp/cross_origin_resource_policy_unittest.cc
@@ -157,7 +157,52 @@
   EXPECT_FALSE(ShouldAllowSameSite("http://127.0.0.1", "http://127.0.0.1"));
 }
 
-TEST(CrossOriginResourcePolicyTest, WithCOEP) {
+void CheckCORP(mojom::RequestMode request_mode,
+               const url::Origin& origin,
+               mojom::URLResponseHeadPtr response_info,
+               const CrossOriginEmbedderPolicy& coep,
+               const DocumentIsolationPolicy& dip,
+               std::optional<mojom::BlockedByResponseReason> expected_result,
+               bool expect_coep_report,
+               bool expect_coep_report_only) {
+  using mojom::RequestDestination;
+  const GURL original_url("https://original.example.com/x/y");
+  const GURL final_url("https://www.example.com/z/u");
+  TestCoepReporter reporter;
+  EXPECT_EQ(expected_result,
+            CrossOriginResourcePolicy::IsBlocked(
+                final_url, original_url, origin, *response_info, request_mode,
+                RequestDestination::kImage, coep, &reporter, dip));
+  if (expect_coep_report && expect_coep_report_only) {
+    ASSERT_EQ(2u, reporter.reports().size());
+    EXPECT_TRUE(reporter.reports()[0].report_only);
+    EXPECT_EQ(reporter.reports()[0].blocked_url, original_url);
+    EXPECT_EQ(reporter.reports()[0].destination, RequestDestination::kImage);
+    EXPECT_FALSE(reporter.reports()[1].report_only);
+    EXPECT_EQ(reporter.reports()[1].blocked_url, original_url);
+    EXPECT_EQ(reporter.reports()[1].destination, RequestDestination::kImage);
+  } else if (expect_coep_report) {
+    ASSERT_EQ(1u, reporter.reports().size());
+    EXPECT_FALSE(reporter.reports()[0].report_only);
+    EXPECT_EQ(reporter.reports()[0].blocked_url, original_url);
+    EXPECT_EQ(reporter.reports()[0].destination, RequestDestination::kImage);
+  } else if (expect_coep_report_only) {
+    ASSERT_EQ(1u, reporter.reports().size());
+    EXPECT_TRUE(reporter.reports()[0].report_only);
+    EXPECT_EQ(reporter.reports()[0].blocked_url, original_url);
+    EXPECT_EQ(reporter.reports()[0].destination, RequestDestination::kImage);
+  } else {
+    EXPECT_TRUE(reporter.reports().empty());
+  }
+}
+
+void RunCORPTestWithCOEPAndDIP(
+    const CrossOriginEmbedderPolicy& coep,
+    const DocumentIsolationPolicy& dip,
+    std::optional<mojom::BlockedByResponseReason> expected_result,
+    bool include_credentials,
+    bool expect_coep_report,
+    bool expect_coep_report_only) {
   mojom::URLResponseHead corp_none;
   mojom::URLResponseHead corp_same_origin;
   mojom::URLResponseHead corp_cross_origin;
@@ -172,182 +217,432 @@
           "HTTP/1.1 200 OK\n"
           "cross-origin-resource-policy: cross-origin\n"));
 
-  const GURL original_url("https://original.example.com/x/y");
-  const GURL final_url("https://www.example.com/z/u");
+  corp_none.request_include_credentials = include_credentials;
+  corp_same_origin.request_include_credentials = include_credentials;
+  corp_cross_origin.request_include_credentials = include_credentials;
+
+  constexpr auto kAllow = std::nullopt;
+  using mojom::RequestMode;
 
   url::Origin destination_origin =
       url::Origin::Create(GURL("https://www.example.com"));
   url::Origin another_origin =
       url::Origin::Create(GURL("https://www2.example.com"));
 
+  // First check that COEP and DIP do not affect the following test cases.
+
+  // 1. Responses with "cross-origin-resource-policy: same-origin" are always
+  // blocked when requested cross-origin.
+  CheckCORP(RequestMode::kNoCors, another_origin, corp_same_origin.Clone(),
+            coep, dip, mojom::BlockedByResponseReason::kCorpNotSameOrigin,
+            false, false);
+
+  // 2. Responses with "cross-origin-resource-policy: cross-origin" are always
+  // allowed.
+  CheckCORP(RequestMode::kNoCors, another_origin, corp_cross_origin.Clone(),
+            coep, dip, kAllow, false, false);
+
+  // 3. Same-origin responses are always allowed.
+  CheckCORP(RequestMode::kNoCors, destination_origin, corp_same_origin.Clone(),
+            coep, dip, kAllow, false, false);
+
+  // 4. Requests whose mode is "cors" are always allowed.
+  CheckCORP(RequestMode::kCors, another_origin, corp_same_origin.Clone(), coep,
+            dip, kAllow, false, false);
+
+  // Now check that a cross-origin request without a CORP header behaves as
+  // expected.
+  CheckCORP(RequestMode::kNoCors, another_origin, corp_none.Clone(), coep, dip,
+            expected_result, expect_coep_report, expect_coep_report_only);
+}
+
+TEST(CrossOriginResourcePolicyTest, WithCOEP) {
   constexpr auto kAllow = std::nullopt;
-  using mojom::RequestDestination;
-  using mojom::RequestMode;
 
   struct TestCase {
-    const RequestMode request_mode;
-    const url::Origin origin;
-    mojom::URLResponseHeadPtr response_info;
-    const std::optional<mojom::BlockedByResponseReason>
-        expectation_with_coep_none;
-    const std::optional<mojom::BlockedByResponseReason>
-        expectation_with_coep_require_corp;
-    const std::optional<mojom::BlockedByResponseReason>
-        expectation_with_coep_credentialless;
+    mojom::CrossOriginEmbedderPolicyValue coep_value;
+    mojom::CrossOriginEmbedderPolicyValue coep_report_only_value;
+    const std::optional<mojom::BlockedByResponseReason> expected_result;
+    bool expect_coep_report;
+    bool expect_coep_report_only;
   } test_cases[] = {
-      // We don't have a cross-origin-resource-policy header on a response. That
-      // leads to blocking when COEP: kRequireCorp is used.
-      {RequestMode::kNoCors, another_origin, corp_none.Clone(), kAllow,
+      {mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::CrossOriginEmbedderPolicyValue::kNone, kAllow, false, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::CrossOriginEmbedderPolicyValue::kNone,
        mojom::BlockedByResponseReason::
            kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+       true, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::CrossOriginEmbedderPolicyValue::kNone,
        mojom::BlockedByResponseReason::
-           kCorpNotSameOriginAfterDefaultedToSameOriginByCoep},
-      // We have "cross-origin-resource-policy: same-origin", so regardless of
-      // COEP the response is blocked.
-      {RequestMode::kNoCors, another_origin, corp_same_origin.Clone(),
-       mojom::BlockedByResponseReason::kCorpNotSameOrigin,
-       mojom::BlockedByResponseReason::kCorpNotSameOrigin,
-       mojom::BlockedByResponseReason::kCorpNotSameOrigin},
-      // We have "cross-origin-resource-policy: cross-origin", so regardless of
-      // COEP the response is allowed.
-      {RequestMode::kNoCors, another_origin, corp_cross_origin.Clone(), kAllow,
-       kAllow, kAllow},
-      // The origin of the request URL and request's origin match, so regardless
-      // of COEP the response is allowed.
-      {RequestMode::kNoCors, destination_origin, corp_same_origin.Clone(),
-       kAllow, kAllow, kAllow},
-      // The request mode is "cors", so so regardless of COEP the response is
-      // allowed.
-      {RequestMode::kCors, another_origin, corp_same_origin.Clone(), kAllow,
-       kAllow, kAllow},
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+       true, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::CrossOriginEmbedderPolicyValue::kRequireCorp, kAllow, false,
+       true},
+      {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+       true, true},
+      {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+       true, true},
+      {mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::CrossOriginEmbedderPolicyValue::kCredentialless, kAllow, false,
+       false},
+      {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+       true, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+       true, false},
   };
 
   for (const auto& test_case : test_cases) {
-    TestCoepReporter reporter;
-    CrossOriginEmbedderPolicy embedder_policy;
-    const bool should_be_blocked_due_to_coep =
-        (test_case.expectation_with_coep_none !=
-         test_case.expectation_with_coep_require_corp);
+    CrossOriginEmbedderPolicy coep;
+    coep.value = test_case.coep_value;
+    coep.report_only_value = test_case.coep_report_only_value;
+    DocumentIsolationPolicy dip;
+    RunCORPTestWithCOEPAndDIP(
+        coep, dip, test_case.expected_result, true /*include_credentials*/,
+        test_case.expect_coep_report, test_case.expect_coep_report_only);
+  }
+}
 
-    // COEP: none, COEP-report-only: none
-    EXPECT_EQ(test_case.expectation_with_coep_none,
-              CrossOriginResourcePolicy::IsBlocked(
-                  final_url, original_url, test_case.origin,
-                  *test_case.response_info, test_case.request_mode,
-                  RequestDestination::kImage, embedder_policy, &reporter));
+TEST(CrossOriginResourcePolicyTest, WithCOEPNoCredentials) {
+  constexpr auto kAllow = std::nullopt;
 
-    EXPECT_TRUE(reporter.reports().empty());
+  struct TestCase {
+    mojom::CrossOriginEmbedderPolicyValue coep_value;
+    mojom::CrossOriginEmbedderPolicyValue coep_report_only_value;
+    const std::optional<mojom::BlockedByResponseReason> expected_result;
+    bool expect_coep_report;
+    bool expect_coep_report_only;
+  } test_cases[] = {
+      {mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::CrossOriginEmbedderPolicyValue::kNone, kAllow, false, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+       true, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::CrossOriginEmbedderPolicyValue::kNone, kAllow, false, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::CrossOriginEmbedderPolicyValue::kRequireCorp, kAllow, false,
+       true},
+      {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+       true, true},
+      {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::CrossOriginEmbedderPolicyValue::kRequireCorp, kAllow, false,
+       true},
+      {mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::CrossOriginEmbedderPolicyValue::kCredentialless, kAllow, false,
+       false},
+      {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+       true, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::CrossOriginEmbedderPolicyValue::kCredentialless, kAllow, false,
+       false},
+  };
 
-    reporter.ClearReports();
-    // COEP: require-corp, COEP-report-only: none
-    embedder_policy.value = mojom::CrossOriginEmbedderPolicyValue::kRequireCorp;
-    EXPECT_EQ(test_case.expectation_with_coep_require_corp,
-              CrossOriginResourcePolicy::IsBlocked(
-                  final_url, original_url, test_case.origin,
-                  *test_case.response_info, test_case.request_mode,
-                  RequestDestination::kImage, embedder_policy, &reporter));
-    if (should_be_blocked_due_to_coep) {
-      ASSERT_EQ(1u, reporter.reports().size());
-      EXPECT_FALSE(reporter.reports()[0].report_only);
-      EXPECT_EQ(reporter.reports()[0].blocked_url, original_url);
-      EXPECT_EQ(reporter.reports()[0].destination, RequestDestination::kImage);
-    } else {
-      EXPECT_TRUE(reporter.reports().empty());
-    }
+  for (const auto& test_case : test_cases) {
+    CrossOriginEmbedderPolicy coep;
+    coep.value = test_case.coep_value;
+    coep.report_only_value = test_case.coep_report_only_value;
+    DocumentIsolationPolicy dip;
+    RunCORPTestWithCOEPAndDIP(
+        coep, dip, test_case.expected_result, false /*include_credentials*/,
+        test_case.expect_coep_report, test_case.expect_coep_report_only);
+  }
+}
 
-    reporter.ClearReports();
-    // COEP: none, COEP-report-only: require-corp
-    embedder_policy.value = mojom::CrossOriginEmbedderPolicyValue::kNone;
-    embedder_policy.report_only_value =
-        mojom::CrossOriginEmbedderPolicyValue::kRequireCorp;
-    EXPECT_EQ(test_case.expectation_with_coep_none,
-              CrossOriginResourcePolicy::IsBlocked(
-                  final_url, original_url, test_case.origin,
-                  *test_case.response_info, test_case.request_mode,
-                  RequestDestination::kScript, embedder_policy, &reporter));
-    if (should_be_blocked_due_to_coep) {
-      ASSERT_EQ(1u, reporter.reports().size());
-      EXPECT_TRUE(reporter.reports()[0].report_only);
-      EXPECT_EQ(reporter.reports()[0].blocked_url, original_url);
-      EXPECT_EQ(reporter.reports()[0].destination, RequestDestination::kScript);
-    } else {
-      EXPECT_TRUE(reporter.reports().empty());
-    }
+TEST(CrossOriginResourcePolicyTest, WithDIP) {
+  constexpr auto kAllow = std::nullopt;
 
-    reporter.ClearReports();
-    // COEP: require-corp, COEP-report-only: require-corp
-    embedder_policy.value = mojom::CrossOriginEmbedderPolicyValue::kRequireCorp;
-    embedder_policy.report_only_value =
-        mojom::CrossOriginEmbedderPolicyValue::kRequireCorp;
-    EXPECT_EQ(test_case.expectation_with_coep_require_corp,
-              CrossOriginResourcePolicy::IsBlocked(
-                  final_url, original_url, test_case.origin,
-                  *test_case.response_info, test_case.request_mode,
-                  RequestDestination::kEmpty, embedder_policy, &reporter));
-    if (should_be_blocked_due_to_coep) {
-      ASSERT_EQ(2u, reporter.reports().size());
-      EXPECT_TRUE(reporter.reports()[0].report_only);
-      EXPECT_EQ(reporter.reports()[0].blocked_url, original_url);
-      EXPECT_EQ(reporter.reports()[0].destination, RequestDestination::kEmpty);
-      EXPECT_FALSE(reporter.reports()[1].report_only);
-      EXPECT_EQ(reporter.reports()[1].blocked_url, original_url);
-      EXPECT_EQ(reporter.reports()[1].destination, RequestDestination::kEmpty);
-    } else {
-      EXPECT_TRUE(reporter.reports().empty());
-    }
+  struct TestCase {
+    mojom::DocumentIsolationPolicyValue dip_value;
+    const std::optional<mojom::BlockedByResponseReason> expected_result;
+  } test_cases[] = {
+      {mojom::DocumentIsolationPolicyValue::kNone, kAllow},
+      {mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByDip},
+      {mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByDip},
+  };
 
-    reporter.ClearReports();
-    // COEP: credentialless, COEP-report-only: none
-    embedder_policy.value =
-        mojom::CrossOriginEmbedderPolicyValue::kCredentialless;
-    EXPECT_EQ(test_case.expectation_with_coep_credentialless,
-              CrossOriginResourcePolicy::IsBlocked(
-                  final_url, original_url, test_case.origin,
-                  *test_case.response_info, test_case.request_mode,
-                  RequestDestination::kImage, embedder_policy, &reporter));
-    if (should_be_blocked_due_to_coep) {
-      ASSERT_EQ(2u, reporter.reports().size());
-      EXPECT_TRUE(reporter.reports()[0].report_only);
-      EXPECT_EQ(reporter.reports()[0].blocked_url, original_url);
-      EXPECT_EQ(reporter.reports()[0].destination, RequestDestination::kImage);
-      EXPECT_FALSE(reporter.reports()[1].report_only);
-      EXPECT_EQ(reporter.reports()[1].blocked_url, original_url);
-      EXPECT_EQ(reporter.reports()[1].destination, RequestDestination::kImage);
-    } else {
-      EXPECT_TRUE(reporter.reports().empty());
-    }
+  for (const auto& test_case : test_cases) {
+    CrossOriginEmbedderPolicy coep;
+    DocumentIsolationPolicy dip(test_case.dip_value);
+    RunCORPTestWithCOEPAndDIP(
+        coep, dip, test_case.expected_result, true /*include_credentials*/,
+        false /*expect_coep_report*/, false /*expect_coep_report_only*/);
+  }
+}
 
-    reporter.ClearReports();
-    // COEP: none, COEP-report-only: credentialless
-    embedder_policy.value = mojom::CrossOriginEmbedderPolicyValue::kNone;
-    embedder_policy.report_only_value =
-        mojom::CrossOriginEmbedderPolicyValue::kCredentialless;
-    EXPECT_EQ(test_case.expectation_with_coep_none,
-              CrossOriginResourcePolicy::IsBlocked(
-                  final_url, original_url, test_case.origin,
-                  *test_case.response_info, test_case.request_mode,
-                  RequestDestination::kScript, embedder_policy, &reporter));
-    EXPECT_TRUE(reporter.reports().empty());
+TEST(CrossOriginResourcePolicyTest, WithDIPNoCredentials) {
+  constexpr auto kAllow = std::nullopt;
 
-    reporter.ClearReports();
-    // COEP: credentialless, COEP-report-only: credentialless
-    embedder_policy.value =
-        mojom::CrossOriginEmbedderPolicyValue::kCredentialless;
-    embedder_policy.report_only_value =
-        mojom::CrossOriginEmbedderPolicyValue::kCredentialless;
-    EXPECT_EQ(test_case.expectation_with_coep_credentialless,
-              CrossOriginResourcePolicy::IsBlocked(
-                  final_url, original_url, test_case.origin,
-                  *test_case.response_info, test_case.request_mode,
-                  RequestDestination::kEmpty, embedder_policy, &reporter));
-    if (should_be_blocked_due_to_coep) {
-      ASSERT_EQ(1u, reporter.reports().size());
-      EXPECT_FALSE(reporter.reports()[0].report_only);
-      EXPECT_EQ(reporter.reports()[0].blocked_url, original_url);
-      EXPECT_EQ(reporter.reports()[0].destination, RequestDestination::kEmpty);
-    } else {
-      EXPECT_TRUE(reporter.reports().empty());
-    }
+  struct TestCase {
+    mojom::DocumentIsolationPolicyValue dip_value;
+    const std::optional<mojom::BlockedByResponseReason> expected_result;
+  } test_cases[] = {
+      {mojom::DocumentIsolationPolicyValue::kNone, kAllow},
+      {mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByDip},
+      {mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless, kAllow},
+  };
+
+  for (const auto& test_case : test_cases) {
+    CrossOriginEmbedderPolicy coep;
+    DocumentIsolationPolicy dip(test_case.dip_value);
+    RunCORPTestWithCOEPAndDIP(
+        coep, dip, test_case.expected_result, false /*include_credentials*/,
+        false /*expect_coep_report*/, false /*expect_coep_report_only*/);
+  }
+}
+
+TEST(CrossOriginResourcePolicyTest, WithCOEPAndDIP) {
+  struct TestCase {
+    mojom::CrossOriginEmbedderPolicyValue coep_value;
+    mojom::CrossOriginEmbedderPolicyValue coep_report_only_value;
+    mojom::DocumentIsolationPolicyValue dip_value;
+    const std::optional<mojom::BlockedByResponseReason> expected_result;
+    bool expect_coep_report;
+    bool expect_coep_report_only;
+  } test_cases[] = {
+      {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+       true, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+       true, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+       false, true},
+      {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+       true, true},
+      {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+       true, true},
+      {mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+       false, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+       true, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+       true, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+       true, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+       true, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+       false, true},
+      {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+       true, true},
+      {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+       true, true},
+      {mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+       false, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+       true, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+       true, false},
+  };
+
+  for (const auto& test_case : test_cases) {
+    CrossOriginEmbedderPolicy coep;
+    coep.value = test_case.coep_value;
+    coep.report_only_value = test_case.coep_report_only_value;
+    DocumentIsolationPolicy dip(test_case.dip_value);
+    RunCORPTestWithCOEPAndDIP(
+        coep, dip, test_case.expected_result, true /*include_credentials*/,
+        test_case.expect_coep_report, test_case.expect_coep_report_only);
+  }
+}
+
+TEST(CrossOriginResourcePolicyTest, WithCOEPAndDIPNoCredentials) {
+  constexpr auto kAllow = std::nullopt;
+  struct TestCase {
+    mojom::CrossOriginEmbedderPolicyValue coep_value;
+    mojom::CrossOriginEmbedderPolicyValue coep_report_only_value;
+    mojom::DocumentIsolationPolicyValue dip_value;
+    const std::optional<mojom::BlockedByResponseReason> expected_result;
+    bool expect_coep_report;
+    bool expect_coep_report_only;
+  } test_cases[] = {
+      {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+       true, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+       false, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+       false, true},
+      {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+       true, true},
+      {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+       false, true},
+      {mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+       false, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+       true, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+       false, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+       true, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless, kAllow,
+       false, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless, kAllow,
+       false, true},
+      {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+       true, true},
+      {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless, kAllow,
+       false, true},
+      {mojom::CrossOriginEmbedderPolicyValue::kNone,
+       mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless, kAllow,
+       false, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+       mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+       mojom::BlockedByResponseReason::
+           kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+       true, false},
+      {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+       mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless, kAllow,
+       false, false},
+  };
+
+  for (const auto& test_case : test_cases) {
+    CrossOriginEmbedderPolicy coep;
+    coep.value = test_case.coep_value;
+    coep.report_only_value = test_case.coep_report_only_value;
+    DocumentIsolationPolicy dip(test_case.dip_value);
+    RunCORPTestWithCOEPAndDIP(
+        coep, dip, test_case.expected_result, false /*include_credentials*/,
+        test_case.expect_coep_report, test_case.expect_coep_report_only);
   }
 }
 
@@ -549,4 +844,5 @@
     }
   }
 }
+
 }  // namespace network
diff --git a/services/network/public/mojom/blocked_by_response_reason.mojom b/services/network/public/mojom/blocked_by_response_reason.mojom
index 6f8d57a..5485a02 100644
--- a/services/network/public/mojom/blocked_by_response_reason.mojom
+++ b/services/network/public/mojom/blocked_by_response_reason.mojom
@@ -12,5 +12,7 @@
   kCoopSandboxedIFrameCannotNavigateToCoopPage,
   kCorpNotSameOrigin,
   kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+  kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+  kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
   kCorpNotSameSite,
 };
diff --git a/services/network/public/mojom/client_security_state.mojom b/services/network/public/mojom/client_security_state.mojom
index 9bd7c41a..3f828835 100644
--- a/services/network/public/mojom/client_security_state.mojom
+++ b/services/network/public/mojom/client_security_state.mojom
@@ -5,6 +5,7 @@
 module network.mojom;
 
 import "services/network/public/mojom/cross_origin_embedder_policy.mojom";
+import "services/network/public/mojom/document_isolation_policy.mojom";
 import "services/network/public/mojom/ip_address_space.mojom";
 
 // How to treat private network requests.
@@ -52,5 +53,8 @@
 
   // The policy to apply to private network requests.
   PrivateNetworkRequestPolicy private_network_request_policy = kAllow;
+
+  // See: https://github.com/explainers-by-googlers/document-isolation-policy
+  DocumentIsolationPolicy document_isolation_policy;
 };
 
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index fa66c32..f5ee349 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -1453,19 +1453,23 @@
   if (memory_cache_)
     memory_cache_->OnRedirect(url_request_.get(), request_destination_);
 
-  const CrossOriginEmbedderPolicy kEmpty;
   // Enforce the Cross-Origin-Resource-Policy (CORP) header.
+  const CrossOriginEmbedderPolicy kEmptyCoep;
   const CrossOriginEmbedderPolicy& cross_origin_embedder_policy =
       factory_params_->client_security_state
           ? factory_params_->client_security_state->cross_origin_embedder_policy
-          : kEmpty;
-
+          : kEmptyCoep;
+  const DocumentIsolationPolicy kEmptyDip;
+  const DocumentIsolationPolicy& document_isolation_policy =
+      factory_params_->client_security_state
+          ? factory_params_->client_security_state->document_isolation_policy
+          : kEmptyDip;
   if (std::optional<mojom::BlockedByResponseReason> blocked_reason =
           CrossOriginResourcePolicy::IsBlocked(
               url_request_->url(), url_request_->original_url(),
               url_request_->initiator(), *response, request_mode_,
               request_destination_, cross_origin_embedder_policy,
-              coep_reporter_)) {
+              coep_reporter_, document_isolation_policy)) {
     CompleteBlockedResponse(net::ERR_BLOCKED_BY_RESPONSE, false,
                             blocked_reason);
     // TODO(crbug.com/40054032):  Close the socket here.
@@ -1778,17 +1782,22 @@
   }
 
   // Enforce the Cross-Origin-Resource-Policy (CORP) header.
-  const CrossOriginEmbedderPolicy kEmpty;
+  const CrossOriginEmbedderPolicy kEmptyCoep;
   const CrossOriginEmbedderPolicy& cross_origin_embedder_policy =
       factory_params_->client_security_state
           ? factory_params_->client_security_state->cross_origin_embedder_policy
-          : kEmpty;
+          : kEmptyCoep;
+  const DocumentIsolationPolicy kEmptyDip;
+  const DocumentIsolationPolicy& document_isolation_policy =
+      factory_params_->client_security_state
+          ? factory_params_->client_security_state->document_isolation_policy
+          : kEmptyDip;
   if (std::optional<mojom::BlockedByResponseReason> blocked_reason =
           CrossOriginResourcePolicy::IsBlocked(
               url_request_->url(), url_request_->original_url(),
               url_request_->initiator(), *response_, request_mode_,
               request_destination_, cross_origin_embedder_policy,
-              coep_reporter_)) {
+              coep_reporter_, document_isolation_policy)) {
     CompleteBlockedResponse(net::ERR_BLOCKED_BY_RESPONSE, false,
                             blocked_reason);
     // Close the socket associated with the request, to prevent leaking
diff --git a/services/network/web_bundle/web_bundle_url_loader_factory.cc b/services/network/web_bundle/web_bundle_url_loader_factory.cc
index 9bdb248..0d83f7f 100644
--- a/services/network/web_bundle/web_bundle_url_loader_factory.cc
+++ b/services/network/web_bundle/web_bundle_url_loader_factory.cc
@@ -885,12 +885,17 @@
   loader->SetBodyLength(payload_length);
 
   // Enforce the Cross-Origin-Resource-Policy (CORP) header.
+  //
+  // TODO(crbug.com/333708501)
+  // Implement support for Document-Isolation-Policy in Web Bundles if needed,
+  // by passing a Document-Isolation-Policy at creation time and using it in the
+  // call below.
   if (std::optional<mojom::BlockedByResponseReason> blocked_reason =
           CrossOriginResourcePolicy::IsBlocked(
               loader->url(), loader->url(), loader->request_initiator(),
               *response_head, loader->request_mode(),
               loader->request_destination(), cross_origin_embedder_policy_,
-              coep_reporter_)) {
+              coep_reporter_, DocumentIsolationPolicy())) {
     loader->CompleteBlockedResponse(net::ERR_BLOCKED_BY_RESPONSE,
                                     blocked_reason);
     return;
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index 5475305..881625d 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -622,6 +622,8 @@
       CoopSandboxedIFrameCannotNavigateToCoopPage
       CorpNotSameOrigin
       CorpNotSameOriginAfterDefaultedToSameOriginByCoep
+      CorpNotSameOriginAfterDefaultedToSameOriginByDip
+      CorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip
       CorpNotSameSite
 
   # Details for a request that has been blocked with the BLOCKED_BY_RESPONSE
@@ -5755,6 +5757,8 @@
       coop-sandboxed-iframe-cannot-navigate-to-coop-page
       corp-not-same-origin
       corp-not-same-origin-after-defaulted-to-same-origin-by-coep
+      corp-not-same-origin-after-defaulted-to-same-origin-by-dip
+      corp-not-same-origin-after-defaulted-to-same-origin-by-coep-and-dip
       corp-not-same-site
 
   # The reason why request was blocked.
diff --git a/third_party/blink/public/platform/resource_request_blocked_reason.h b/third_party/blink/public/platform/resource_request_blocked_reason.h
index 601a8095..02310b1c 100644
--- a/third_party/blink/public/platform/resource_request_blocked_reason.h
+++ b/third_party/blink/public/platform/resource_request_blocked_reason.h
@@ -20,6 +20,8 @@
   kCoopSandboxedIFrameCannotNavigateToCoopPage,
   kCorpNotSameOrigin,
   kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+  kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+  kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
   kCorpNotSameSite,
   kConversionRequest,
   kSupervisedUserUrlBlocked,
diff --git a/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc b/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc
index 27267c8cf..6d7b86c 100644
--- a/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc
@@ -319,6 +319,14 @@
         kCorpNotSameOriginAfterDefaultedToSameOriginByCoep:
       return protocol::Audits::BlockedByResponseReasonEnum::
           CorpNotSameOriginAfterDefaultedToSameOriginByCoep;
+    case network::mojom::BlockedByResponseReason::
+        kCorpNotSameOriginAfterDefaultedToSameOriginByDip:
+      return protocol::Audits::BlockedByResponseReasonEnum::
+          CorpNotSameOriginAfterDefaultedToSameOriginByDip;
+    case network::mojom::BlockedByResponseReason::
+        kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip:
+      return protocol::Audits::BlockedByResponseReasonEnum::
+          CorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip;
     case network::mojom::BlockedByResponseReason::kCorpNotSameSite:
       return protocol::Audits::BlockedByResponseReasonEnum::CorpNotSameSite;
   }
diff --git a/third_party/blink/renderer/core/inspector/inspector_issue_conversion.cc b/third_party/blink/renderer/core/inspector/inspector_issue_conversion.cc
index 68419e5b..aba69f9 100644
--- a/third_party/blink/renderer/core/inspector/inspector_issue_conversion.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_issue_conversion.cc
@@ -286,6 +286,14 @@
         kCorpNotSameOriginAfterDefaultedToSameOriginByCoep:
       return protocol::Audits::BlockedByResponseReasonEnum::
           CorpNotSameOriginAfterDefaultedToSameOriginByCoep;
+    case network::mojom::blink::BlockedByResponseReason::
+        kCorpNotSameOriginAfterDefaultedToSameOriginByDip:
+      return protocol::Audits::BlockedByResponseReasonEnum::
+          CorpNotSameOriginAfterDefaultedToSameOriginByDip;
+    case network::mojom::blink::BlockedByResponseReason::
+        kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip:
+      return protocol::Audits::BlockedByResponseReasonEnum::
+          CorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip;
     case network::mojom::blink::BlockedByResponseReason::kCorpNotSameSite:
       return protocol::Audits::BlockedByResponseReasonEnum::CorpNotSameSite;
   }
diff --git a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
index da6f704..146f6fc 100644
--- a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
@@ -419,6 +419,14 @@
         kCorpNotSameOriginAfterDefaultedToSameOriginByCoep:
       return protocol::Network::BlockedReasonEnum::
           CorpNotSameOriginAfterDefaultedToSameOriginByCoep;
+    case blink::ResourceRequestBlockedReason::
+        kCorpNotSameOriginAfterDefaultedToSameOriginByDip:
+      return protocol::Network::BlockedReasonEnum::
+          CorpNotSameOriginAfterDefaultedToSameOriginByDip;
+    case blink::ResourceRequestBlockedReason::
+        kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip:
+      return protocol::Network::BlockedReasonEnum::
+          CorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip;
     case blink::ResourceRequestBlockedReason::kCorpNotSameSite:
       return protocol::Network::BlockedReasonEnum::CorpNotSameSite;
     case ResourceRequestBlockedReason::kConversionRequest:
diff --git a/third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.cc b/third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.cc
index 359b8e4..dbb6c73 100644
--- a/third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.cc
+++ b/third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.cc
@@ -43,7 +43,8 @@
              GURL(response.InternalURLList().front()), initiator_origin,
              corp_header_value, request_mode, request_destination,
              response.GetResponse()->RequestIncludeCredentials(), policy_,
-             reporter_ ? reporter_.get() : nullptr)
+             reporter_ ? reporter_.get() : nullptr,
+             network::DocumentIsolationPolicy())
       .has_value();
 }
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_error.cc b/third_party/blink/renderer/platform/loader/fetch/resource_error.cc
index f8af836..efce505 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_error.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_error.cc
@@ -235,6 +235,14 @@
         kCorpNotSameOriginAfterDefaultedToSameOriginByCoep:
       return blink::ResourceRequestBlockedReason::
           kCorpNotSameOriginAfterDefaultedToSameOriginByCoep;
+    case network::mojom::BlockedByResponseReason::
+        kCorpNotSameOriginAfterDefaultedToSameOriginByDip:
+      return blink::ResourceRequestBlockedReason::
+          kCorpNotSameOriginAfterDefaultedToSameOriginByDip;
+    case network::mojom::BlockedByResponseReason::
+        kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip:
+      return blink::ResourceRequestBlockedReason::
+          kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip;
     case network::mojom::BlockedByResponseReason::kCorpNotSameSite:
       return blink::ResourceRequestBlockedReason::kCorpNotSameSite;
   }
@@ -314,6 +322,14 @@
         kCorpNotSameOriginAfterDefaultedToSameOriginByCoep:
       detail = "NotSameOriginAfterDefaultedToSameOriginByCoep";
       break;
+    case ResourceRequestBlockedReason::
+        kCorpNotSameOriginAfterDefaultedToSameOriginByDip:
+      detail = "NotSameOriginAfterDefaultedToSameOriginByDip";
+      break;
+    case ResourceRequestBlockedReason::
+        kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip:
+      detail = "NotSameOriginAfterDefaultedToSameOriginByCoepAndDip";
+      break;
     case ResourceRequestBlockedReason::kCorpNotSameSite:
       detail = "NotSameSite";
       break;
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 07311ad7..b2096d57 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -3064,5 +3064,22 @@
       "syg@chromium.org",
       "samuelmaddock@electronjs.org"
     ]
+  },
+  {
+    "prefix": "document-isolation-policy",
+    "platforms": [
+      "Linux"
+    ],
+    "bases": [
+      "external/wpt/html/document-isolation-policy"
+    ],
+    "exclusive_tests": "ALL",
+    "args": [
+      "--enable-features=DocumentIsolationPolicy"
+    ],
+    "expires": "Nov 16, 2024",
+    "owners": [
+      "clamy@chromium.org"
+    ]
   }
 ]
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/DIR_METADATA
new file mode 100644
index 0000000..ed39007
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/DIR_METADATA
@@ -0,0 +1,4 @@
+team_email: "chrome-security-owp-team@google.com"
+buganizer_public: {
+  component_id: 1552691
+}
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/README.md b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/README.md
new file mode 100644
index 0000000..59f039e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/README.md
@@ -0,0 +1 @@
+This directory contains tests for `Document-Isolation-Policy`.
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/isolate-and-require-corp.tentative.https.html b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/isolate-and-require-corp.tentative.https.html
new file mode 100644
index 0000000..df4bd47
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/isolate-and-require-corp.tentative.https.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta name="timeout" content="long">
+<title>Document-Isolation-Policy: isolate-and-require-corp header and subresources</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script> <!-- Use token() to allow running tests in parallel -->
+<div id=log></div>
+<script>
+const HOST = get_host_info();
+const BASE = new URL("resources", location).pathname;
+
+promise_test(async t => {
+  const response = await fetch(get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-cross-origin-corp.js", {mode: "no-cors"});
+  assert_equals(response.type, "opaque");
+}, `"isolate-and-require-corp" top-level: fetch() to CORP: cross-origin response should succeed`);
+
+promise_test(async t => {
+  return promise_rejects_js(t, TypeError, fetch(get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js", {mode: "no-cors"}));
+}, `"isolate-and-require-corp" top-level: fetch() to cross-origin response without CORP should fail`);
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/isolate-and-require-corp.tentative.https.html.headers b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/isolate-and-require-corp.tentative.https.html.headers
new file mode 100644
index 0000000..bcc6f073
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/isolate-and-require-corp.tentative.https.html.headers
@@ -0,0 +1 @@
+Document-Isolation-Policy: isolate-and-require-corp
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/fetch-and-create-url.html b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/fetch-and-create-url.html
new file mode 100644
index 0000000..6b0f962
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/fetch-and-create-url.html
@@ -0,0 +1,91 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Fetch and create Blob</title>
+<script>
+  async function responseToBlob(response) {
+    let blob;
+    try {
+      blob = await response.blob();
+    } catch (e) {
+      return { error: `blob error: ${e.name}` };
+    }
+
+    return { url: URL.createObjectURL(blob) };
+  }
+
+  async function responseToData(response) {
+    const mimeType = response.headers.get("content-type");
+
+    let text;
+    try {
+      text = await response.text();
+    } catch(e) {
+      return { error: `text error: ${e.name}` };
+    }
+
+    return { url: `data:${mimeType},${encodeURIComponent(text)}` };
+  }
+
+  async function responseToFilesystem(response) {
+    if (!window.webkitRequestFileSystem) {
+      return { error: "unimplemented" };
+    }
+
+    let blob;
+    try {
+      blob = await response.blob();
+    } catch (e) {
+      return { error: `blob error: ${e.name}` };
+    }
+
+    const fs = await new Promise(resolve => {
+      window.webkitRequestFileSystem(window.TEMPORARY, 1024*1024, resolve);
+    });
+
+    const file = await new Promise(resolve => {
+      fs.root.getFile('fetch-and-create-url', { create: true }, resolve);
+    });
+
+    const writer = await new Promise(resolve => file.createWriter(resolve));
+
+    try {
+      await new Promise((resolve, reject) => {
+        writer.onwriteend = resolve;
+        writer.onerror = reject;
+        writer.write(blob);
+      });
+    } catch (e) {
+      return { error: `file write error: ${e.name}` };
+    }
+
+    return { url: file.toURL() };
+  }
+
+  async function responseToScheme(response, scheme) {
+    switch (scheme) {
+      case "blob":
+        return responseToBlob(response);
+      case "data":
+        return responseToData(response);
+      case "filesystem":
+        return responseToFilesystem(response);
+      default:
+        return { error: `unknown scheme: ${scheme}` };
+    }
+  }
+
+  async function fetchToScheme(url, scheme) {
+    let response;
+    try {
+      response = await fetch(url);
+    } catch (e) {
+      return { error: `fetch error: ${e.name}` };
+    }
+
+    return responseToScheme(response, scheme);
+  }
+
+  const params = new URL(window.location).searchParams;
+  fetchToScheme(params.get("url"), params.get("scheme"))
+    .then((message) => { parent.postMessage(message, "*"); });
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/nothing-cross-origin-corp.js b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/nothing-cross-origin-corp.js
new file mode 100644
index 0000000..662e936
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/nothing-cross-origin-corp.js
@@ -0,0 +1 @@
+/* Just an empty JS file */
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/nothing-cross-origin-corp.js.headers b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/nothing-cross-origin-corp.js.headers
new file mode 100644
index 0000000..1b88136c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/nothing-cross-origin-corp.js.headers
@@ -0,0 +1 @@
+Cross-Origin-Resource-Policy: cross-origin
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/nothing-no-corp.js b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/nothing-no-corp.js
new file mode 100644
index 0000000..662e936
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/nothing-no-corp.js
@@ -0,0 +1 @@
+/* Just an empty JS file */
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/shared-worker-fetch.js.py b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/shared-worker-fetch.js.py
new file mode 100644
index 0000000..bf46cd2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/shared-worker-fetch.js.py
@@ -0,0 +1,24 @@
+body = b'''
+'use strict';
+
+onconnect = (event) => {
+  const port = event.ports[0];
+
+  port.onmessage = (event) => {
+    fetch(event.data, { mode: 'no-cors' })
+      .then(
+        () => port.postMessage('success'),
+        () => port.postMessage('failure')
+      );
+  };
+
+  port.postMessage('ready');
+};'''
+
+def main(request, response):
+    headers = [(b'Content-Type', b'text/javascript')]
+
+    for value in request.GET.get_list(b'value'):
+        headers.append((b'Document-Isolation-Policy', value))
+
+    return (200, headers, body)
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/shared-worker.js b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/shared-worker.js
new file mode 100644
index 0000000..c5f2c3cc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/shared-worker.js
@@ -0,0 +1,7 @@
+onconnect = (event) => {
+  const port = event.ports[0];
+  port.onmessage = (event) => {
+    eval(event.data);
+  };
+  port.postMessage('ready');
+};
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/worker-support.js b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/worker-support.js
new file mode 100644
index 0000000..349b4eb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/worker-support.js
@@ -0,0 +1,81 @@
+// Configures `url` such that the response carries a `COEP: ${value}` header.
+//
+// `url` must be a `URL` instance.
+function setDip(url, value) {
+  url.searchParams
+      .set("pipe", `header(document-isolation-policy,${value})`);
+}
+
+// Resolves the given `relativeUrl` relative to the current window's location.
+//
+// `options` can contain the following keys:
+//
+// - `dip`: value passed to `setDip()`, if present.
+// - `host`: overrides the host of the returned URL.
+//
+// Returns a `URL` instance.
+function resolveUrl(relativeUrl, options) {
+  const url = new URL(relativeUrl, window.location);
+
+  if (options !== undefined) {
+    const { dip, host } = options;
+    if (dip !== undefined) {
+      setDip(url, dip);
+    }
+    if (host !== undefined) {
+      url.host = host;
+    }
+  }
+
+  return url;
+}
+
+// Adds an iframe loaded from `url` to the current document, waiting for it to
+// load before returning.
+//
+// The returned iframe is removed from the document at the end of the test `t`.
+async function withIframe(t, url) {
+  const frame = document.createElement("iframe");
+  frame.src = url;
+
+  t.add_cleanup(() => frame.remove());
+
+  const loadedPromise = new Promise(resolve => {
+    frame.addEventListener('load', resolve, {once: true});
+  });
+  document.body.append(frame);
+  await loadedPromise;
+
+  return frame;
+}
+
+// Asynchronously waits for a single "message" event on the given `target`.
+function waitForMessage(target) {
+  return new Promise(resolve => {
+    target.addEventListener('message', resolve, {once: true});
+  });
+}
+
+// Fetches `url` from a document with DIP `creatorDip`, then serializes it
+// and returns a URL pointing to the fetched body with the given `scheme`.
+//
+// - `creatorDip` is passed to `setDip()`.
+// - `scheme` may be one of: "blob", "data" or "filesystem".
+//
+// The returned URL is valid until the end of the test `t`.
+async function createLocalUrl(t, { url, creatorDip, scheme }) {
+  const frameUrl = resolveUrl("resources/fetch-and-create-url.html", {
+    dip: creatorDip,
+  });
+  frameUrl.searchParams.set("url", url);
+  frameUrl.searchParams.set("scheme", scheme);
+
+  const messagePromise = waitForMessage(window);
+  const frame = await withIframe(t, frameUrl);
+
+  const evt = await messagePromise;
+  const message = evt.data;
+  assert_equals(message.error, undefined, "url creation error");
+
+  return message.url;
+}
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/shared-workers.tentative.https.html b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/shared-workers.tentative.https.html
new file mode 100644
index 0000000..d0a186f4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/shared-workers.tentative.https.html
@@ -0,0 +1,235 @@
+<!doctype html>
+<html>
+<meta charset="utf-8">
+<title>COEP - policy derivation for Shared Workers</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="resources/worker-support.js"></script>
+<body>
+<p>Verify the Document Isolation Policy for Shared Workers by performing a
+cross-origin "fetch" request for a resource that does not specify CORP. Only
+Shared Workers with the default DIP should be able to successfully perform
+this operation.</p>
+<script>
+'use strict';
+
+function makeWorkerUrl(options) {
+  return resolveUrl("resources/shared-worker-fetch.js.py", options);
+}
+
+/**
+ * Create a Shared Worker within an iframe
+ *
+ * @param {object} t - a testharness.js subtest instance (used to reset global
+ *                     state)
+ * @param {string} url - the URL from which the Shared Worker should be
+ *                       created
+ * @param {string} options.ownerDip - the Document Isolation Policy of the
+                                       iframe
+ */
+async function createWorker(t, url, options) {
+  const { ownerDip } = options || {};
+  const frameUrl = resolveUrl("/common/blank.html", { dip: ownerDip });
+
+  const iframe = await withIframe(t, frameUrl);
+
+  const sw = new iframe.contentWindow.SharedWorker(url);
+  sw.onerror = t.unreached_func('SharedWorker.onerror should not be called');
+
+  await new Promise((resolve) => {
+    sw.port.addEventListener('message', resolve, { once: true });
+    sw.port.start();
+  });
+
+  return sw;
+}
+
+/**
+ * Instruct a Shared Worker to fetch from a specified URL and report on the
+ * success of the operation.
+ *
+ * @param {SharedWorker} worker
+ * @param {string} url - the URL that the worker should fetch
+ */
+function fetchFromWorker(worker, url) {
+  return new Promise((resolve) => {
+    worker.port.postMessage(url);
+    worker.port.addEventListener(
+      'message', (event) => resolve(event.data), { once: true }
+    );
+  });
+};
+
+promise_test(async (t) => {
+  const worker = await createWorker(t, makeWorkerUrl());
+  const result = await fetchFromWorker(worker,
+   get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+  assert_equals(result, 'success');
+}, 'default policy (derived from response)');
+
+promise_test(async (t) => {
+  const worker = await createWorker(t, makeWorkerUrl({ dip: 'isolate-and-require-corp' }));
+  const result = await fetchFromWorker(worker,
+   get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+  assert_equals(result, 'failure');
+}, '"isolate-and-require-corp" (derived from response)');
+
+promise_test(async (t) => {
+  const blobUrl = await createLocalUrl(t, {
+    url: makeWorkerUrl(),
+    scheme: "blob",
+  });
+
+  const workers = await Promise.all([
+    createWorker(t, blobUrl),
+    createWorker(t, blobUrl),
+    createWorker(t, blobUrl),
+  ]);
+
+  const result = await fetchFromWorker(workers[0],
+   get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+  assert_equals(result, 'success');
+}, 'default policy (derived from owner set due to use of local scheme - blob URL)');
+
+promise_test(async (t) => {
+  const blobUrl = await createLocalUrl(t, {
+    url: makeWorkerUrl(),
+    creatorDip: "isolate-and-require-corp",
+    scheme: "blob",
+  });
+
+  const workers = await Promise.all([
+    createWorker(t, blobUrl),
+    createWorker(t, blobUrl),
+    createWorker(t, blobUrl),
+  ]);
+
+  const result = await fetchFromWorker(workers[0],
+   get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+  assert_equals(result, 'failure');
+}, 'isolate-and-require-corp (derived from blob URL creator)');
+
+promise_test(async (t) => {
+  const blobUrl = await createLocalUrl(t, {
+    url: makeWorkerUrl(),
+    scheme: "blob",
+  });
+
+  const workers = await Promise.all([
+    createWorker(t, blobUrl),
+    createWorker(t, blobUrl, { ownerDip: 'isolate-and-require-corp' }),
+    createWorker(t, blobUrl),
+  ]);
+
+  const result = await fetchFromWorker(workers[0],
+   get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+  assert_equals(result, 'failure');
+}, '"isolate-and-require-corp" (derived from owner set due to use of local scheme - blob URL)');
+
+promise_test(async (t) => {
+  const dataUrl = await createLocalUrl(t, {
+    url: makeWorkerUrl(),
+    scheme: "data",
+  });
+
+  const workers = await Promise.all([
+    createWorker(t, dataUrl),
+    createWorker(t, dataUrl),
+    createWorker(t, dataUrl),
+  ]);
+
+  const result = await fetchFromWorker(workers[0],
+   get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+  assert_equals(result, 'success');
+}, 'default policy (derived from owner set due to use of local scheme - data URL)');
+
+promise_test(async (t) => {
+  const dataUrl = await createLocalUrl(t, {
+    url: makeWorkerUrl(),
+    creatorDip: "isolate-and-require-corp",
+    scheme: "data",
+  });
+
+  const workers = await Promise.all([
+    createWorker(t, dataUrl),
+    createWorker(t, dataUrl),
+    createWorker(t, dataUrl),
+  ]);
+
+  const result = await fetchFromWorker(workers[0],
+   get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+  assert_equals(result, 'success');
+}, 'default policy (not derived from data URL creator)');
+
+promise_test(async (t) => {
+  const dataUrl = await createLocalUrl(t, {
+    url: makeWorkerUrl(),
+    scheme: "data",
+  });
+
+  const workers = await Promise.all([
+    createWorker(t, dataUrl),
+    createWorker(t, dataUrl, { ownerdip: 'isolate-and-require-corp' }),
+    createWorker(t, dataUrl),
+  ]);
+
+  const result = await fetchFromWorker(workers[0],
+   get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+  assert_equals(result, 'failure');
+}, '"isolate-and-require-corp" (derived from owner set due to use of local scheme - data URL)');
+
+promise_test(async (t) => {
+  const filesystemUrl = await createLocalUrl(t, {
+    url: makeWorkerUrl(),
+    scheme: "filesystem",
+  });
+
+  const workers = await Promise.all([
+    createWorker(t, filesystemUrl),
+    createWorker(t, filesystemUrl),
+    createWorker(t, filesystemUrl),
+  ]);
+
+  const result = await fetchFromWorker(workers[0],
+   get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+  assert_equals(result, 'success');
+}, 'default policy (derived from owner set due to use of local scheme - filesystem URL)');
+
+promise_test(async (t) => {
+  const filesystemUrl = await createLocalUrl(t, {
+    url: makeWorkerUrl(),
+    creatorDip: "isolate-and-require-corp",
+    scheme: "filesystem",
+  });
+
+  const workers = await Promise.all([
+    createWorker(t, filesystemUrl),
+    createWorker(t, filesystemUrl),
+    createWorker(t, filesystemUrl),
+  ]);
+
+  const result = await fetchFromWorker(workers[0],
+   get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+  assert_equals(result, 'failure');
+}, 'isolate-and-require-corp (derived from filesystem URL creator)');
+
+promise_test(async (t) => {
+  const filesystemUrl = await createLocalUrl(t, {
+    url: makeWorkerUrl(),
+    scheme: "filesystem",
+  });
+
+  const workers = await Promise.all([
+    createWorker(t, filesystemUrl),
+    createWorker(t, filesystemUrl, { ownerDip: 'isolate-and-require-corp' }),
+    createWorker(t, filesystemUrl),
+  ]);
+
+  const result = await fetchFromWorker(workers[0],
+   get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+  assert_equals(result, 'failure');
+}, '"isolate-and-require-corp" (derived from owner set due to use of local scheme - filesystem URL)');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/virtual/document-isolation-policy/README.md b/third_party/blink/web_tests/virtual/document-isolation-policy/README.md
new file mode 100644
index 0000000..a19fdea
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/document-isolation-policy/README.md
@@ -0,0 +1,2 @@
+This suite runs document-isolation-policy WPTs with
+--enable-features=DocumentIsolationPolicy.
diff --git a/third_party/blink/web_tests/virtual/document-isolation-policy/external/wpt/html/document-isolation-policy/shared-workers.tentative.https-expected.txt b/third_party/blink/web_tests/virtual/document-isolation-policy/external/wpt/html/document-isolation-policy/shared-workers.tentative.https-expected.txt
new file mode 100644
index 0000000..2070916
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/document-isolation-policy/external/wpt/html/document-isolation-policy/shared-workers.tentative.https-expected.txt
@@ -0,0 +1,15 @@
+This is a testharness.js-based test.
+[FAIL] isolate-and-require-corp (derived from blob URL creator)
+  assert_equals: expected "failure" but got "success"
+[FAIL] "isolate-and-require-corp" (derived from owner set due to use of local scheme - blob URL)
+  assert_equals: expected "failure" but got "success"
+[FAIL] "isolate-and-require-corp" (derived from owner set due to use of local scheme - data URL)
+  assert_equals: expected "failure" but got "success"
+[FAIL] default policy (derived from owner set due to use of local scheme - filesystem URL)
+  assert_unreached: SharedWorker.onerror should not be called Reached unreachable code
+[FAIL] isolate-and-require-corp (derived from filesystem URL creator)
+  assert_unreached: SharedWorker.onerror should not be called Reached unreachable code
+[FAIL] "isolate-and-require-corp" (derived from owner set due to use of local scheme - filesystem URL)
+  assert_unreached: SharedWorker.onerror should not be called Reached unreachable code
+Harness: the test ran to completion.
+