diff --git a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
index 8dc9bac392eac15ca673acab3b507e6851e8814f..6fc54a38c00f23ce78f265a8906462d2a5325714 100644
--- a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
@@ -123,8 +123,10 @@ public function onRespond(ResponseEvent $event) {
     // different from the declared content-type, since that can lead to
     // XSS and other vulnerabilities.
     // https://owasp.org/www-project-secure-headers
-    $response->headers->set('X-Content-Type-Options', 'nosniff', FALSE);
-    $response->headers->set('X-Frame-Options', 'SAMEORIGIN', FALSE);
+    $response->headers->set('X-Content-Type-Options', 'nosniff');
+    if (!$response->headers->has('X-Frame-Options')) {
+      $response->headers->set('X-Frame-Options', 'SAMEORIGIN');
+    }
 
     // If the current response isn't an implementation of the
     // CacheableResponseInterface, we assume that a Response is either
diff --git a/core/tests/Drupal/Tests/Core/EventSubscriber/FinishResponseSubscriberTest.php b/core/tests/Drupal/Tests/Core/EventSubscriber/FinishResponseSubscriberTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a77403daf411dab819ece948708a8b33d944cd6e
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/EventSubscriber/FinishResponseSubscriberTest.php
@@ -0,0 +1,133 @@
+<?php
+
+namespace Drupal\Tests\Core\EventSubscriber;
+
+use Drupal\Core\Cache\Context\CacheContextsManager;
+use Drupal\Core\EventSubscriber\FinishResponseSubscriber;
+use Drupal\Core\Language\Language;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\PageCache\RequestPolicyInterface;
+use Drupal\Core\PageCache\ResponsePolicyInterface;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\ResponseHeaderBag;
+use Symfony\Component\HttpKernel\Event\ResponseEvent;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+
+/**
+ * @coversDefaultClass \Drupal\Core\EventSubscriber\FinishResponseSubscriber
+ * @group EventSubscriber
+ */
+class FinishResponseSubscriberTest extends UnitTestCase {
+
+  /**
+   * The mock Kernel.
+   *
+   * @var \Symfony\Component\HttpKernel\HttpKernelInterface|\PHPUnit\Framework\MockObject\MockObject
+   */
+  protected $kernel;
+
+  /**
+   * The mock language manager.
+   *
+   * @var \Drupal\Core\Language\LanguageManagerInterface|\PHPUnit\Framework\MockObject\MockObject
+   */
+  protected $languageManager;
+
+  /**
+   * The mock request policy.
+   *
+   * @var \Drupal\Core\PageCache\RequestPolicyInterface|\PHPUnit\Framework\MockObject\MockObject
+   */
+  protected $requestPolicy;
+
+  /**
+   * The mock response policy.
+   *
+   * @var \Drupal\Core\PageCache\ResponsePolicyInterface|\PHPUnit\Framework\MockObject\MockObject
+   */
+  protected $responsePolicy;
+
+  /**
+   * The mock cache contexts manager.
+   *
+   * @var \Drupal\Core\Cache\Context\CacheContextsManager|\PHPUnit\Framework\MockObject\MockObject
+   */
+  protected $cacheContextsManager;
+
+  protected function setUp(): void {
+    parent::setUp();
+
+    $this->kernel = $this->createMock(HttpKernelInterface::class);
+    $this->languageManager = $this->createMock(LanguageManagerInterface::class);
+    $this->requestPolicy = $this->createMock(RequestPolicyInterface::class);
+    $this->responsePolicy = $this->createMock(ResponsePolicyInterface::class);
+    $this->cacheContextsManager = $this->createMock(CacheContextsManager::class);
+  }
+
+  /**
+   * Finish subscriber should set some default header values.
+   *
+   * @covers ::onRespond
+   */
+  public function testDefaultHeaders() {
+    $finishSubscriber = new FinishResponseSubscriber(
+      $this->languageManager,
+      $this->getConfigFactoryStub(),
+      $this->requestPolicy,
+      $this->responsePolicy,
+      $this->cacheContextsManager,
+      FALSE
+    );
+
+    $this->languageManager->method('getCurrentLanguage')
+      ->willReturn(new Language(['id' => 'en']));
+
+    $request = $this->createMock(Request::class);
+    $response = $this->createMock(Response::class);
+    $response->headers = new ResponseHeaderBag();
+    $event = new ResponseEvent($this->kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response);
+
+    $finishSubscriber->onRespond($event);
+
+    $this->assertEquals(['en'], $response->headers->all('Content-language'));
+    $this->assertEquals(['nosniff'], $response->headers->all('X-Content-Type-Options'));
+    $this->assertEquals(['SAMEORIGIN'], $response->headers->all('X-Frame-Options'));
+  }
+
+  /**
+   * Finish subscriber should not overwrite existing header values.
+   *
+   * @covers ::onRespond
+   */
+  public function testExistingHeaders() {
+    $finishSubscriber = new FinishResponseSubscriber(
+      $this->languageManager,
+      $this->getConfigFactoryStub(),
+      $this->requestPolicy,
+      $this->responsePolicy,
+      $this->cacheContextsManager,
+      FALSE
+    );
+
+    $this->languageManager->method('getCurrentLanguage')
+      ->willReturn(new Language(['id' => 'en']));
+
+    $request = $this->createMock(Request::class);
+    $response = $this->createMock(Response::class);
+    $response->headers = new ResponseHeaderBag();
+    $event = new ResponseEvent($this->kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response);
+
+    $response->headers->set('X-Content-Type-Options', 'foo');
+    $response->headers->set('X-Frame-Options', 'DENY');
+
+    $finishSubscriber->onRespond($event);
+
+    $this->assertEquals(['en'], $response->headers->all('Content-language'));
+    // 'X-Content-Type-Options' will be unconditionally set by the core.
+    $this->assertEquals(['nosniff'], $response->headers->all('X-Content-Type-Options'));
+    $this->assertEquals(['DENY'], $response->headers->all('X-Frame-Options'));
+  }
+
+}