diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-23494-AddStdWrapToConfigadditionalHeaders.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-23494-AddStdWrapToConfigadditionalHeaders.rst
new file mode 100644
index 0000000000000000000000000000000000000000..6cb9bf64e3dd54f7c68a03208d31834ff540dec3
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-23494-AddStdWrapToConfigadditionalHeaders.rst
@@ -0,0 +1,27 @@
+.. include:: ../../Includes.txt
+
+=========================================================
+Feature: #23494 - Add stdWrap to config.additionalHeaders
+=========================================================
+
+See :issue:`23494`
+
+Description
+===========
+
+Add stdWrap to the elements of the additionalHeaders array. This gives full control over sending an HTTP header.
+
+.. code-block:: typoscript
+
+	config.additionalHeaders {
+	  10.header = foo:
+	  10.header.dataWrap = |{page:uid}
+	}
+
+
+Impact
+======
+
+Allow to use stdWrap on the elements `header`, `replace` and `httpResponseCode`. Empty headers will be skipped now.
+
+.. index:: TypoScript
diff --git a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
index 5b0ecdce6aedfb5f4ed21316086d4f9895645207..1bc53348d98f27b602ce67039399599f83693be2 100644
--- a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
+++ b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
@@ -3506,17 +3506,7 @@ class TypoScriptFrontendController
             $this->sendCacheHeaders();
         }
         // Set headers, if any
-        if (is_array($this->config['config']['additionalHeaders.'])) {
-            ksort($this->config['config']['additionalHeaders.']);
-            foreach ($this->config['config']['additionalHeaders.'] as $options) {
-                header(
-                    trim($options['header']),
-                    // "replace existing headers" is turned on by default, unless turned off
-                    ($options['replace'] !== '0'),
-                    ((int)$options['httpResponseCode'] ?: null)
-                );
-            }
-        }
+        $this->sendAdditionalHeaders();
         // Send appropriate status code in case of temporary content
         if ($this->tempContent) {
             $this->addTempContentHttpHeaders();
@@ -4570,6 +4560,47 @@ class TypoScriptFrontendController
         }
     }
 
+    /**
+     * Send additional headers from config.additionalHeaders
+     *
+     * @see \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController::processOutput()
+     */
+    protected function sendAdditionalHeaders()
+    {
+        if (!isset($this->config['config']['additionalHeaders.'])) {
+            return;
+        }
+        ksort($this->config['config']['additionalHeaders.']);
+        foreach ($this->config['config']['additionalHeaders.'] as $options) {
+            if (!is_array($options)) {
+                continue;
+            }
+            $header = $options['header'] ?? '';
+            $header = isset($options['header.'])
+                ? $this->cObj->stdWrap(trim($header), $options['header.'])
+                : trim($header);
+            if ($header === '') {
+                continue;
+            }
+            $replace = $options['replace'] ?? '';
+            $replace = isset($options['replace.'])
+                ? $this->cObj->stdWrap($replace, $options['replace.'])
+                : $replace;
+            $httpResponseCode = $options['httpResponseCode'] ?? '';
+            $httpResponseCode = isset($options['httpResponseCode.'])
+                ? $this->cObj->stdWrap($httpResponseCode, $options['httpResponseCode.'])
+                : $httpResponseCode;
+            $httpResponseCode = (int)$httpResponseCode;
+
+            header(
+                $header,
+                // "replace existing headers" is turned on by default, unless turned off
+                $replace !== '0',
+                $httpResponseCode ?: null
+            );
+        }
+    }
+
     /**
      * Returns the current BE user.
      *
diff --git a/typo3/sysext/t3editor/Resources/Private/tsref.xml b/typo3/sysext/t3editor/Resources/Private/tsref.xml
index a17cf510daaab2b571ba6a72ff2083210a750028..69ecad8a54f3125a386f7362f9fdc98d79679f50 100644
--- a/typo3/sysext/t3editor/Resources/Private/tsref.xml
+++ b/typo3/sysext/t3editor/Resources/Private/tsref.xml
@@ -207,19 +207,33 @@ Note: If you're working on a server where you have both internal and external ac
 			<default><![CDATA[
 ]]></default>
 		</property>
-		<property name="additionalHeaders" type="string">
-			<description><![CDATA[strings divided by "|"
-      This is additional headers. You separate each header by a vertical line "|".  Normally TYPO3 does not send any headers with the Header()-function in PHP.
+		<property name="additionalHeaders" type="additionalHeadersArray">
+			<description><![CDATA[This property can be used to define additional HTTP headers.
 
-Examples:
-Content-Type: text/vnd.wap.wml
-(this will sent a content-header for a WAP-site)
+For each numeric index, there are the following sub-properties:
+
+header: The header string.
+
+replace: Optional. If set, previous headers with the same name are replaced with the current one. Default is "1".
+
+httpResponseCode: Optional. HTTP status code as an integer.
 
-Content-Type: image/gif | Expires: Mon, 26 Jul 1997 05:00:00 GMT
-(this will sent a content-header for a GIF-file and a Expires header)
+Example:
+
+config.additionalHeaders {
+   10 {
+      # The header string
+      header = WWW-Authenticate: Negotiate
 
-Location: www.typo3.org
-(This redirects the page to www.typo3.org)]]></description>
+      # Do not replace previous headers with the same name.
+      replace = 0
+
+      # Force a 401 HTTP response code
+      httpResponseCode = 401
+   }
+   # Always set cache headers to private, overwriting the default TYPO3 Cache-control header
+   20.header = Cache-control: Private
+}]]></description>
 			<default><![CDATA[
 ]]></default>
 		</property>
@@ -6998,4 +7012,48 @@ The userfunction must return an <A>-tag.]]></description>
 ]]></description>
 		</property>
 	</type>
+	<type id="additionalHeadersArray" extends="array">
+		<property name="10" type="additionalHeadersItem">
+			<description><![CDATA[Defines a header.
+
+Must at least contain the header property.]]></description>
+			<default><![CDATA[]]></default>
+		</property>
+		<property name="20" type="additionalHeadersItem">
+			<description><![CDATA[Defines a header.
+
+Must at least contain the header property.]]></description>
+			<default><![CDATA[]]></default>
+		</property>
+		<property name="30" type="additionalHeadersItem">
+			<description><![CDATA[Defines a header.
+
+Must at least contain the header property.]]></description>
+			<default><![CDATA[]]></default>
+		</property>
+		<property name="40" type="additionalHeadersItem">
+			<description><![CDATA[Defines a header.
+
+Must at least contain the header property.]]></description>
+			<default><![CDATA[]]></default>
+		</property>
+	</type>
+	<type id="additionalHeadersItem">
+		<property name="header" type="stdWrap">
+			<description><![CDATA[The header string]]></description>
+			<default><![CDATA[]]></default>
+		</property>
+		<property name="replace" type="stdWrap">
+			<description><![CDATA[Optional.
+
+If set, previous headers with the same name are replaced with the current one.
+
+Default is "1".]]></description>
+			<default><![CDATA[1]]></default>
+		</property>
+		<property name="httpResponseCode" type="stdWrap">
+			<description><![CDATA[Optional. HTTP status code as an integer.]]></description>
+			<default><![CDATA[]]></default>
+		</property>
+	</type>
 </tsRef>