diff --git a/modules/xray_audit_insight/src/OEmbed/ResourceFetcherDecorator.php b/modules/xray_audit_insight/src/OEmbed/ResourceFetcherDecorator.php
new file mode 100644
index 0000000000000000000000000000000000000000..d6ea11fe1364609a306a7754824152cdfe195e50
--- /dev/null
+++ b/modules/xray_audit_insight/src/OEmbed/ResourceFetcherDecorator.php
@@ -0,0 +1,46 @@
+<?php
+
+namespace Drupal\xray_audit_insight\OEmbed;
+
+use Drupal\media\OEmbed\ResourceFetcherInterface;
+use Drupal\media\OEmbed\ResourceException;
+use Drupal\xray_audit_insight\XrayAuditInsightReport;
+
+/**
+ * Decorates the original ResourceFetcher service to add logging capabilities.
+ */
+class ResourceFetcherDecorator implements ResourceFetcherInterface {
+
+  /**
+   * Constructs a new ResourceFetcherDecorator.
+   *
+   * @param \Drupal\media\OEmbed\ResourceFetcherInterface $resourceFetcher
+   *   The original resource fetcher service.
+   * @param \Drupal\xray_audit_insight\XrayAuditInsightReport $insightReport
+   *   The XrayAuditInsightReport service for logging insights.
+   */
+  public function __construct(
+    protected ResourceFetcherInterface $resourceFetcher,
+    protected XrayAuditInsightReport $insightReport,
+  ) {}
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fetchResource($url) {
+    try {
+      return $this->resourceFetcher->fetchResource($url);
+    }
+    catch (ResourceException $e) {
+      // Log the exception to the xray_audit_insight table.
+      $this->insightReport->addInsightData(
+        'external_resource',
+        $e->getMessage(),
+        $url
+      );
+
+      throw $e;
+    }
+  }
+
+}
diff --git a/modules/xray_audit_insight/src/Plugin/insights/XrayAuditExternalResourcesInsight.php b/modules/xray_audit_insight/src/Plugin/insights/XrayAuditExternalResourcesInsight.php
new file mode 100644
index 0000000000000000000000000000000000000000..23ebd00d832358bebf59405c6a1a30157f93951d
--- /dev/null
+++ b/modules/xray_audit_insight/src/Plugin/insights/XrayAuditExternalResourcesInsight.php
@@ -0,0 +1,85 @@
+<?php
+
+namespace Drupal\xray_audit_insight\Plugin\insights;
+
+use Drupal\Core\Url;
+use Drupal\Core\Link;
+use Drupal\xray_audit_insight\Plugin\XrayAuditInsightPluginBase;
+use Drupal\xray_audit\Plugin\XrayAuditTaskPluginInterface;
+
+/**
+ * Plugin implementation for external resources needing review.
+ *
+ * @XrayAuditInsightPlugin (
+ *   id = "external_resources_review",
+ *   label = @Translation("External resources needing review"),
+ *   description = @Translation("Identified external resources that should be reviewed"),
+ *   sort = 7
+ * )
+ */
+class XrayAuditExternalResourcesInsight extends XrayAuditInsightPluginBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $taskPluginId = 'external_resources';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $operation = 'external_resources';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getInsightsForDrupalReport(): array {
+    $insights = $this->getInsights();
+    $needs_review = $insights['external_resources_review'];
+    if ($needs_review) {
+      $url = Url::fromUserInput($this->getPathReport($this->taskPluginId, $this->operation));
+      $reports_link = Link::fromTextAndUrl($this->t('task report'), $url);
+      $value = $this->t('External resources should be reviewed. Please check the @report_link for details', [
+        '@report_link' => $reports_link->toString(),
+      ]);
+      $severity = REQUIREMENT_WARNING;
+    }
+    else {
+      $value = $this->t("No external resources need review.");
+      $severity = NULL;
+    }
+
+    return [
+      'external_resources_review' => $this->buildInsightForDrupalReport(
+        $this->label(),
+        $value,
+        '',
+        $severity
+      ),
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getInsights(): array {
+    return ['external_resources_review' => $this->existResourcesNeedingReview()];
+  }
+
+  /**
+   * Check if there are external resources needing review.
+   *
+   * @return bool
+   *   True if there are resources needing review.
+   */
+  protected function existResourcesNeedingReview(): bool {
+    $task_plugin = $this->getInstancedPlugin($this->taskPluginId, $this->operation);
+    $result = $task_plugin instanceof XrayAuditTaskPluginInterface ? $task_plugin->getDataOperationResult($this->operation) : [];
+    foreach ($result as $resource) {
+      if (!empty($resource->needs_review)) {
+        return TRUE;
+      }
+    }
+    return FALSE;
+  }
+
+}
diff --git a/modules/xray_audit_insight/src/XrayAuditInsightReport.php b/modules/xray_audit_insight/src/XrayAuditInsightReport.php
new file mode 100644
index 0000000000000000000000000000000000000000..e0cabe9095a194f52893d1bb13f542c0de8b27a1
--- /dev/null
+++ b/modules/xray_audit_insight/src/XrayAuditInsightReport.php
@@ -0,0 +1,103 @@
+<?php
+
+namespace Drupal\xray_audit_insight;
+
+use Drupal\Core\Database\Connection;
+
+/**
+ * Service for managing the xray_audit_insight table.
+ */
+class XrayAuditInsightReport {
+
+  /**
+   * The database connection.
+   *
+   * @var \Drupal\Core\Database\Connection
+   */
+  protected $database;
+
+  /**
+   * Constructs a new XrayAuditInsightReport object.
+   *
+   * @param \Drupal\Core\Database\Connection $database
+   *   The database connection.
+   */
+  public function __construct(Connection $database) {
+    $this->database = $database;
+  }
+
+  /**
+   * Adds a new insight with text data to the xray_audit_insight table.
+   *
+   * Only adds the record if no record with the same type and data exists.
+   *
+   * @param string $type
+   *   The type of the insight.
+   * @param string $message
+   *   The message associated with the insight.
+   * @param string $url
+   *   The URL to be stored.
+   *
+   * @return bool
+   *   TRUE if a new record was added, FALSE if a duplicate was found.
+   */
+  public function addInsightData(string $type, string $message, string $url) {
+    $data = $url;
+
+    // Check if a record with the same type and data already exists.
+    $exists = $this->database->select('xray_audit_insight', 'xai')
+      ->fields('xai', ['id'])
+      ->condition('type', $type)
+      ->condition('data', $data)
+      ->condition('message', $message)
+      ->range(0, 1)
+      ->execute()
+      ->fetchField();
+
+    // Only insert if no matching record exists.
+    if (!$exists) {
+      $this->database->insert('xray_audit_insight')
+        ->fields([
+          'type' => $type,
+          'data' => $data,
+          'message' => $message,
+        ])
+        ->execute();
+      return TRUE;
+    }
+
+    return FALSE;
+  }
+
+  /**
+   * Gets insights for a specific external resource URL.
+   *
+   * @param string $normalized_url
+   *   The normalized URL to check.
+   *
+   * @return array
+   *   Array of matching insights.
+   */
+  public function getExternalResourceInsights(string $normalized_url) {
+    $query = $this->database->select('xray_audit_insight', 'xai')
+      ->fields('xai')
+      ->condition('type', 'external_resource')
+      ->condition('data', $normalized_url);
+    return $query->execute()->fetchAll();
+  }
+
+  /**
+   * Cleans up orphaned external resource insights that don't match any media.
+   *
+   * @param array $normalized_urls
+   *   Array of active normalized URLs.
+   */
+  public function cleanupOrphanedExternalResourceInsights(array $normalized_urls) {
+
+    $this->database->delete('xray_audit_insight')
+      ->condition('data', $normalized_urls, 'NOT IN')
+      ->execute();
+
+  }
+
+}
diff --git a/modules/xray_audit_insight/xray_audit_insight.install b/modules/xray_audit_insight/xray_audit_insight.install
new file mode 100644
index 0000000000000000000000000000000000000000..89204dffc9ffbcdb73570024444a55f464c5cfc4
--- /dev/null
+++ b/modules/xray_audit_insight/xray_audit_insight.install
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the xray_audit_insight module.
+ */
+
+/**
+ * Implements hook_schema().
+ */
+function xray_audit_insight_schema() {
+  $schema['xray_audit_insight'] = [
+    'description' => 'Stores xray audit insight data',
+    'fields' => [
+      'id' => [
+        'type' => 'serial',
+        'not null' => TRUE,
+        'description' => 'Primary Key: Unique insight ID.',
+      ],
+      'type' => [
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'description' => 'Insight type.',
+      ],
+      'message' => [
+        'type' => 'text',
+        'size' => 'big',
+        'not null' => FALSE,
+        'description' => 'Text data containing insight information.',
+      ],
+      'data' => [
+        'type' => 'text',
+        'size' => 'big',
+        'not null' => FALSE,
+        'description' => 'Text data containing insight information.',
+      ],
+    ],
+    'primary key' => ['id'],
+    'indexes' => [
+      'type' => ['type'],
+    ],
+  ];
+
+  return $schema;
+}
+
+/**
+ * Create xray_audit_insight table.
+ */
+function xray_audit_insight_update_9001() {
+  $schema = \Drupal::database()->schema();
+  $table_name = 'xray_audit_insight';
+
+  if (!$schema->tableExists($table_name)) {
+    $schema->createTable($table_name, xray_audit_insight_schema()[$table_name]);
+  }
+}
diff --git a/modules/xray_audit_insight/xray_audit_insight.services.yml b/modules/xray_audit_insight/xray_audit_insight.services.yml
index 0a6dcb5574ab9387a909ef7aaf2c26ffdfb796b2..fec69cccb01cc65b27dfbb32cfb3d6c6b1c504dc 100644
--- a/modules/xray_audit_insight/xray_audit_insight.services.yml
+++ b/modules/xray_audit_insight/xray_audit_insight.services.yml
@@ -2,3 +2,14 @@ services:
   plugin_manager.xray_audit_insight:
     class: Drupal\xray_audit_insight\Plugin\XrayAuditInsightPluginManager
     parent: default_plugin_manager
+
+  xray_audit_insight.report:
+    class: Drupal\xray_audit_insight\XrayAuditInsightReport
+    arguments: ['@database']
+
+  xray_audit_insight.resource_fetcher:
+    class: Drupal\xray_audit_insight\OEmbed\ResourceFetcherDecorator
+    arguments: [ '@xray_audit_insight.resource_fetcher.inner', '@xray_audit_insight.report']
+    decorates: media.oembed.resource_fetcher
+    decoration_priority: 10
+    public: false
diff --git a/src/Plugin/xray_audit/tasks/ContentDisplay/XrayAuditExternalResourcesPlugin.php b/src/Plugin/xray_audit/tasks/ContentDisplay/XrayAuditExternalResourcesPlugin.php
new file mode 100644
index 0000000000000000000000000000000000000000..adaad2e4827c92127a4483dac0c0ea02cdd79cdf
--- /dev/null
+++ b/src/Plugin/xray_audit/tasks/ContentDisplay/XrayAuditExternalResourcesPlugin.php
@@ -0,0 +1,314 @@
+<?php
+
+namespace Drupal\xray_audit\Plugin\xray_audit\tasks\ContentDisplay;
+
+use Drupal\Component\Utility\Html;
+use Drupal\xray_audit\Plugin\XrayAuditTaskPluginBase;
+use Drupal\xray_audit\Utils\XrayAuditTableFilter;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Plugin implementation of external resources.
+ *
+ * @XrayAuditTaskPlugin (
+ *   id = "external_resources",
+ *   label = @Translation("External Resources"),
+ *   description = @Translation("External resources referenced in content."),
+ *   group = "content_display",
+ *   sort = 2,
+ *   operations = {
+ *     "external_resources" = {
+ *       "label" = "External Resources",
+ *       "description" = "Lists external resources referenced in content"
+ *     }
+ *   }
+ * )
+ */
+class XrayAuditExternalResourcesPlugin extends XrayAuditTaskPluginBase {
+
+  /**
+   * The entity type manager service.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * The entity field manager service.
+   *
+   * @var \Drupal\Core\Entity\EntityFieldManagerInterface
+   */
+  protected $entityFieldManager;
+
+  /**
+   * The module handler service.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
+   * The XrayAuditInsightReport service.
+   *
+   * @var \Drupal\xray_audit_insight\XrayAuditInsightReport|null
+   */
+  protected $insightReport;
+
+  /**
+   * The URL resolver service.
+   *
+   * @var \Drupal\media\OEmbed\UrlResolverInterface
+   */
+  protected $urlResolver;
+
+  /**
+   * The link generator service.
+   *
+   * @var \Drupal\Core\Utility\LinkGeneratorInterface
+   */
+  protected $linkGenerator;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    $instance = new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition
+    );
+    $instance->entityTypeManager = $container->get('entity_type.manager');
+    $instance->entityFieldManager = $container->get('entity_field.manager');
+    $instance->moduleHandler = $container->get('module_handler');
+    $instance->linkGenerator = $container->get('link_generator');
+
+    if ($instance->moduleHandler->moduleExists('media')) {
+      $instance->urlResolver = $container->get('media.oembed.url_resolver');
+    }
+    // Check if xray_audit_insight module is enabled.
+    if ($instance->moduleHandler->moduleExists('xray_audit_insight')) {
+      $instance->insightReport = $container->get('xray_audit_insight.report');
+
+    }
+
+    return $instance;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDataOperationResult(string $operation = '') {
+    if (!$this->moduleHandler->moduleExists('media')) {
+      return [];
+    }
+
+    $oembed_fields = $this->getOembedFields();
+    $results = $this->processMediaEntities($oembed_fields);
+    $this->cleanupInsights($results);
+
+    return $results;
+  }
+
+  /**
+   * Gets all OEmbed fields from media bundles.
+   */
+  private function getOembedFields(): array {
+    $oembed_fields = [];
+    $bundles = $this->entityTypeManager->getStorage('media_type')->loadMultiple();
+    $display_storage = $this->entityTypeManager->getStorage('entity_view_display');
+
+    foreach ($bundles as $bundle_id => $bundle) {
+      $displays = $display_storage->loadByProperties([
+        'targetEntityType' => 'media',
+        'bundle' => $bundle_id,
+      ]);
+
+      foreach ($displays as $display) {
+        foreach ($display->getComponents() as $field_name => $component) {
+          if (isset($component['type']) && str_contains($component['type'], 'oembed')) {
+            $oembed_fields[$bundle_id][$field_name] = $field_name;
+          }
+        }
+      }
+    }
+
+    return $oembed_fields;
+  }
+
+  /**
+   * Process media entities and collect results.
+   */
+  private function processMediaEntities(array $oembed_fields): array {
+    $results = [];
+    $media_storage = $this->entityTypeManager->getStorage('media');
+
+    foreach ($oembed_fields as $bundle_id => $field_names) {
+      $media_ids = $media_storage->getQuery()
+        ->condition('bundle', $bundle_id)
+        ->accessCheck(FALSE)
+        ->execute();
+
+      if (empty($media_ids)) {
+        continue;
+      }
+
+      $media_entities = $media_storage->loadMultiple($media_ids);
+      foreach ($media_entities as $media_id => $media) {
+        $this->processMediaEntity($media, $media_id, $bundle_id, $field_names, $results);
+      }
+    }
+
+    return $results;
+  }
+
+  /**
+   * Process a single media entity.
+   */
+  private function processMediaEntity($media, $media_id, $bundle_id, array $field_names, array &$results): void {
+    foreach ($field_names as $field_name) {
+      if (!$media->hasField($field_name) || $media->get($field_name)->isEmpty()) {
+        continue;
+      }
+
+      foreach ($media->get($field_name) as $field_item) {
+        $value = $field_item->getValue();
+        if (!isset($value['value'])) {
+          continue;
+        }
+
+        $result = $this->createBaseResult($media_id, $bundle_id, $value['value'], $media);
+        $this->addInsightData($result, $value['value']);
+        $results[] = (object) $result;
+      }
+    }
+  }
+
+  /**
+   * Creates base result array for a media item.
+   */
+  private function createBaseResult($media_id, $bundle_id, $resource_url, $media): array {
+    return [
+      'entity_id' => $media_id,
+      'entity_type' => 'media',
+      'bundle' => $bundle_id,
+      'resource' => $resource_url,
+      'edit_url' => $media->toUrl('edit-form'),
+      'needs_review' => FALSE,
+      'insight_message' => '',
+    ];
+  }
+
+  /**
+   * Adds insight data to the result.
+   */
+  private function addInsightData(array &$result, string $resource_url): void {
+    if (!$this->insightReport) {
+      return;
+    }
+
+    try {
+      $normalized_url = $this->urlResolver->getResourceUrl($resource_url);
+      $insights = $this->insightReport->getExternalResourceInsights($normalized_url);
+
+      if (!empty($insights)) {
+        $result['needs_review'] = TRUE;
+        $result['insight_message'] = end($insights)->message;
+      }
+    }
+    catch (\Exception $e) {
+      $this->insightReport->addInsightData('external_resource', $e->getMessage(), $resource_url);
+      $result['needs_review'] = TRUE;
+      $result['insight_message'] = $e->getMessage();
+    }
+  }
+
+  /**
+   * Cleanup orphaned insights.
+   */
+  private function cleanupInsights(array $results): void {
+    if (!$this->insightReport) {
+      return;
+    }
+
+    $media_urls = array_reduce($results, function ($urls, $result) {
+      $urls[] = $result->resource;
+      try {
+        $urls[] = $this->urlResolver->getResourceUrl($result->resource);
+      }
+      catch (\Exception) {
+        // Ignore URL resolution errors.
+      }
+      return $urls;
+    }, []);
+
+    $this->insightReport->cleanupOrphanedExternalResourceInsights($media_urls);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildDataRenderArray(array $data, string $operation = '') {
+    $build = [];
+
+    $rows = [];
+
+    $headers = [
+      $this->t('Entity ID'),
+      $this->t('Entity Type'),
+      $this->t('Bundle'),
+      $this->t('Resource URL'),
+      $this->t('Edit'),
+    ];
+
+    foreach ($data as $row) {
+      $highlight = FALSE;
+      $row_data = [
+        $row->entity_id ?? '',
+        $row->entity_type ?? '',
+        $row->bundle ?? '',
+        $row->resource ?? '',
+        $this->linkGenerator->generate($this->t('Edit'), $row->edit_url) ?? '',
+      ];
+
+      // Add insight columns if xray_audit_insight module is enabled.
+      if ($this->moduleHandler->moduleExists('xray_audit_insight')) {
+        $row_data[] = isset($row->needs_review) && $row->needs_review ? $this->t('Yes') : $this->t('No');
+        $row_data[] = $row->insight_message ?? '';
+        $highlight = isset($row->needs_review) && $row->needs_review;
+      }
+
+      $rows[] = ['data' => $row_data, 'class' => $highlight ? ['xray-audit--highlighted'] : []];
+    }
+
+    // Add insight headers if xray_audit_insight module is enabled.
+    if ($this->moduleHandler->moduleExists('xray_audit_insight')) {
+      $headers[] = $this->t('Needs Review');
+      $headers[] = $this->t('Message');
+    }
+    $unique_id = Html::getUniqueId('xray-audit-external-resources');
+    $build['table'] = [
+      '#theme' => 'table',
+      '#header' => $headers,
+      '#sticky' => TRUE,
+      '#weight' => 10,
+      '#rows' => $rows,
+      '#empty' => $this->t('No external resources found'),
+      '#attributes' => [
+        'class' => ['xray-audit__table'],
+        'id' => $unique_id,
+      ],
+      '#attached' => [
+        'library' => [
+          'xray_audit/xray_audit',
+        ],
+      ],
+    ];
+
+    $columns_indexes = [0, 1, 2, 3, 4, 5, 6];
+    $build['filter'] = XrayAuditTableFilter::generateRenderableFilterInput($unique_id, $columns_indexes, NULL, $headers);
+    $build['filter']['#weight'] = 6;
+
+    return $build;
+  }
+
+}