diff --git a/automatic_updates_extensions/automatic_updates_extensions.services.yml b/automatic_updates_extensions/automatic_updates_extensions.services.yml
index a91eeee366a3e935f34d2cbde316f3731d8abaf0..acac491c30d1580bf01acea0732407717f8331ea 100644
--- a/automatic_updates_extensions/automatic_updates_extensions.services.yml
+++ b/automatic_updates_extensions/automatic_updates_extensions.services.yml
@@ -6,6 +6,9 @@ services:
   Drupal\automatic_updates_extensions\Validator\UpdateReleaseValidator:
     tags:
       - { name: event_subscriber }
+  Drupal\automatic_updates_extensions\Validator\ForbidCoreChangesValidator:
+    tags:
+      - { name: event_subscriber }
   Drupal\automatic_updates_extensions\Validator\RequestedUpdateValidator:
     tags:
       - { name: event_subscriber }
diff --git a/automatic_updates_extensions/src/Validator/ForbidCoreChangesValidator.php b/automatic_updates_extensions/src/Validator/ForbidCoreChangesValidator.php
new file mode 100644
index 0000000000000000000000000000000000000000..6be66670c2725392edfcb3ffdf61a7343d803b14
--- /dev/null
+++ b/automatic_updates_extensions/src/Validator/ForbidCoreChangesValidator.php
@@ -0,0 +1,110 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\automatic_updates_extensions\Validator;
+
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\Url;
+use Drupal\package_manager\ComposerInspector;
+use Drupal\package_manager\Event\PreApplyEvent;
+use Drupal\package_manager\Event\StatusCheckEvent;
+use Drupal\package_manager\InstalledPackagesList;
+use Drupal\package_manager\PathLocator;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Validates that no changes were made to Drupal Core packages.
+ *
+ * @internal
+ *   This is an internal part of Automatic Updates and may be changed or removed
+ *   at any time without warning. External code should not interact with this
+ *   class.
+ */
+final class ForbidCoreChangesValidator implements EventSubscriberInterface {
+
+  use StringTranslationTrait;
+
+  public function __construct(
+    private readonly PathLocator $pathLocator,
+    private readonly ComposerInspector $composerInspector,
+  ) {}
+
+  /**
+   * Validates the staged packages.
+   *
+   * @param \Drupal\package_manager\Event\StatusCheckEvent|\Drupal\package_manager\Event\PreApplyEvent $event
+   *   The event object.
+   */
+  public function validateStagedCorePackages(StatusCheckEvent|PreApplyEvent $event): void {
+    $stage = $event->stage;
+    // We only want to do this check if the stage belongs to Automatic Updates
+    // Extensions.
+    if ($stage->getType() !== 'automatic_updates_extensions:attended' || !$stage->stageDirectoryExists()) {
+      return;
+    }
+    $active_core_packages = $this->getInstalledCorePackages($this->pathLocator->getProjectRoot());
+    $stage_core_packages = $this->getInstalledCorePackages($stage->getStageDirectory());
+
+    $new_packages = $stage_core_packages->getPackagesNotIn($active_core_packages);
+    $removed_packages = $active_core_packages->getPackagesNotIn($stage_core_packages);
+    $changed_packages = $active_core_packages->getPackagesWithDifferentVersionsIn($stage_core_packages);
+
+    $error_messages = [];
+    foreach ($new_packages as $new_package) {
+      $error_messages[] = $this->t("'@name' installed.", ['@name' => $new_package->name]);
+    }
+    foreach ($removed_packages as $removed_package) {
+      $error_messages[] = $this->t("'@name' removed.", ['@name' => $removed_package->name]);
+    }
+    foreach ($changed_packages as $name => $updated_package) {
+      $error_messages[] = $this->t(
+        "'@name' version changed from @active_version to @staged_version.",
+        [
+          '@name' => $updated_package->name,
+          '@staged_version' => $stage_core_packages[$name]->version,
+          '@active_version' => $updated_package->version,
+        ]
+      );
+
+    }
+    if ($error_messages) {
+      $event->addError($error_messages, $this->t(
+        'Updating Drupal Core while updating extensions is currently not supported. Use <a href=":url">this form</a> to update Drupal core. The following changes were made to the Drupal core packages:',
+        [':url' => Url::fromRoute('update.report_update')->toString()]
+      ));
+    }
+  }
+
+  /**
+   * Gets all the installed core packages for a given project root.
+   *
+   * This method differs from
+   * \Drupal\package_manager\ComposerInspector::getInstalledPackagesList in that
+   * it ensures that the 'drupal/core' is included in the list if present.
+   *
+   * @param string $composer_root
+   *   The path to the composer root.
+   *
+   * @return \Drupal\package_manager\InstalledPackagesList
+   *   The installed core packages.
+   */
+  private function getInstalledCorePackages(string $composer_root): InstalledPackagesList {
+    $installed_package_list = $this->composerInspector->getInstalledPackagesList($composer_root);
+    $core_packages = $installed_package_list->getCorePackages();
+    if (isset($installed_package_list['drupal/core']) && !isset($core_packages['drupal/core'])) {
+      $core_packages = new InstalledPackagesList(array_merge($core_packages->getArrayCopy(), ['drupal/core' => $installed_package_list['drupal/core']]));
+    }
+    return $core_packages;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents(): array {
+    $events[StatusCheckEvent::class][] = ['validateStagedCorePackages'];
+    $events[PreApplyEvent::class][] = ['validateStagedCorePackages'];
+    return $events;
+  }
+
+}
diff --git a/automatic_updates_extensions/tests/src/Kernel/Validator/ForbidCoreChangesValidatorTest.php b/automatic_updates_extensions/tests/src/Kernel/Validator/ForbidCoreChangesValidatorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a6b3f7027206fe1ad200ce52e091381b936bc956
--- /dev/null
+++ b/automatic_updates_extensions/tests/src/Kernel/Validator/ForbidCoreChangesValidatorTest.php
@@ -0,0 +1,133 @@
+<?php
+
+namespace Drupal\Tests\automatic_updates_extensions\Kernel\Validator;
+
+use Drupal\automatic_updates_extensions\ExtensionUpdateStage;
+use Drupal\package_manager\Exception\StageEventException;
+use Drupal\package_manager\ValidationResult;
+use Drupal\Tests\automatic_updates_extensions\Kernel\AutomaticUpdatesExtensionsKernelTestBase;
+
+/**
+ * @coversDefaultClass \Drupal\automatic_updates_extensions\Validator\ForbidCoreChangesValidator
+ * @group automatic_updates_extensions
+ * @internal
+ */
+class ForbidCoreChangesValidatorTest extends AutomaticUpdatesExtensionsKernelTestBase {
+
+  /**
+   * Tests error messages if requested updates were not staged.
+   *
+   * @param array $staged_versions
+   *   An array of the staged versions where the keys are the package names and
+   *   the values are the package versions or NULL if the package should be
+   *   removed in the stage.
+   * @param string[][] $new_packages
+   *   An array of the new packages to add to the stage.
+   * @param ValidationResult[] $expected_results
+   *   The expected validation results.
+   *
+   * @dataProvider providerTestErrorMessage
+   */
+  public function testErrorMessages(array $staged_versions, array $new_packages, array $expected_results): void {
+    $this->setReleaseMetadata([
+      'semver_test' => __DIR__ . '/../../../fixtures/release-history/semver_test.1.1.xml',
+      'drupal' => __DIR__ . '/../../../../../package_manager/tests/fixtures/release-history/drupal.9.8.2.xml',
+    ]);
+    $this->getStageFixtureManipulator()->addPackage([
+      'name' => 'drupal/non-core',
+      'version' => '1.0.0',
+      'type' => 'package',
+    ]);
+
+    foreach ($staged_versions as $package => $version) {
+      if ($version === NULL) {
+        $this->getStageFixtureManipulator()->removePackage($package);
+        continue;
+      }
+      $this->getStageFixtureManipulator()->setVersion($package, $version);
+    }
+    foreach ($new_packages as $package) {
+      $this->getStageFixtureManipulator()->addPackage($package);
+    }
+    $this->getStageFixtureManipulator()->setVersion('drupal/semver_test', '8.1.1');
+
+    $stage = $this->container->get(ExtensionUpdateStage::class);
+    $stage->begin([
+      'semver_test' => '8.1.1',
+    ]);
+    $stage->stage();
+    $this->assertStatusCheckResults($expected_results, $stage);
+    try {
+      $stage->apply();
+      $this->fail('Expecting an exception.');
+    }
+    catch (StageEventException $exception) {
+      $this->assertExpectedResultsFromException($expected_results, $exception);
+    }
+  }
+
+  /**
+   * Data provider for testErrorMessage().
+   *
+   * @return mixed[]
+   *   The test cases.
+   */
+  public function providerTestErrorMessage(): array {
+    $summary = t('Updating Drupal Core while updating extensions is currently not supported. Use <a href="/admin/reports/updates/update">this form</a> to update Drupal core. The following changes were made to the Drupal core packages:');
+    return [
+      'drupal/core updated, non-core updated' => [
+        [
+          'drupal/core' => '9.8.1',
+          'drupal/non-core' => '1.0.1',
+        ],
+        [],
+        [ValidationResult::createError([t("'drupal/core' version changed from 9.8.0 to 9.8.1.")], $summary)],
+      ],
+      'drupal/core-recommended and drupal/core updated, non-core package installed' => [
+        [
+          'drupal/core-recommended' => '9.8.1',
+          'drupal/core' => '9.8.1',
+        ],
+        [
+          [
+            'name' => 'other-org/other-package',
+            'type' => 'package',
+          ],
+        ],
+        [
+          ValidationResult::createError(
+            [
+              t("'drupal/core-recommended' version changed from 9.8.0 to 9.8.1."),
+              t("'drupal/core' version changed from 9.8.0 to 9.8.1."),
+            ],
+            $summary
+          ),
+        ],
+      ],
+      'drupal/core-recommended removed, drupal/core updated, drupal/core-composer-scaffold installed, non-core package removed' => [
+        [
+          'drupal/core-recommended' => NULL,
+          'drupal/core' => '9.8.1',
+          'drupal/non-core' => NULL,
+        ],
+        [
+          [
+            'name' => 'drupal/core-composer-scaffold',
+            'type' => 'package',
+          ],
+        ],
+        [
+          ValidationResult::createError(
+            [
+              t("'drupal/core-composer-scaffold' installed."),
+              t("'drupal/core-recommended' removed."),
+              t("'drupal/core' version changed from 9.8.0 to 9.8.1."),
+            ],
+            $summary
+          ),
+        ],
+      ],
+    ];
+  }
+
+}