TYPO3 vulnerable to Arbitrary Code Execution via Form Framework
Description
TYPO3 is an open source PHP based web content management system. Versions prior to 8.7.49, 9.5.38, 10.4.33, 11.5.20, and 12.1.1 are vulnerable to Code Injection. Due to the lack of separating user-submitted data from the internal configuration in the Form Designer backend module, it is possible to inject code instructions to be processed and executed via TypoScript as PHP code. The existence of individual TypoScript instructions for a particular form item and a valid backend user account with access to the form module are needed to exploit this vulnerability. This issue is patched in versions 8.7.49 ELTS, 9.5.38 ELTS, 10.4.33, 11.5.20, 12.1.1.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
TYPO3 Form Designer backend module lacks input separation, allowing authenticated code injection via TypoScript as PHP.
A code injection vulnerability exists in the Form Designer backend module of the TYPO3 CMS. The root cause is the failure to properly separate user-submitted data from internal configuration, enabling an attacker to inject code instructions that are processed and executed via TypoScript as PHP code [1].
Exploitation
Prerequisites Exploitation requires the attacker to have a valid backend user account with access to the form module, and the targeted form item must have individual TypoScript instructions defined [1]. The attack surface is limited to authenticated users, but a low-privileged backend user could potentially craft a payload within form YAML configuration files to achieve code execution [3].
Impact
Successful exploitation allows an attacker to execute arbitrary PHP code on the server, leading to full compromise of the affected TYPO3 instance. The vulnerability is classified as critical and requires no user interaction beyond the authenticated session [1].
Mitigation
The issue has been patched in TYPO3 versions 8.7.49 ELTS, 9.5.38 ELTS, 10.4.33, 11.5.20, and 12.1.1 [1]. The fix prohibits the evaluation of TypoScript look-alike instructions in form YAML settings, as demonstrated in the upstream commit [3]. Upgrading to one of the patched versions is strongly recommended.
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
typo3/cms-corePackagist | >= 8.0.0, < 8.7.49 | 8.7.49 |
typo3/cms-corePackagist | >= 9.0.0, < 9.5.38 | 9.5.38 |
typo3/cms-corePackagist | >= 10.0.0, < 10.4.33 | 10.4.33 |
typo3/cms-corePackagist | >= 11.0.0, < 11.5.20 | 11.5.20 |
typo3/cms-corePackagist | >= 12.0.0, < 12.1.1 | 12.1.1 |
typo3/cmsPackagist | >= 10.0.0, < 10.4.33 | 10.4.33 |
typo3/cmsPackagist | >= 11.0.0, < 11.5.20 | 11.5.20 |
typo3/cmsPackagist | >= 12.0.0, < 12.1.1 | 12.1.1 |
Affected products
4- osv-coords3 versions
>= 8.0.0, < 8.7.49+ 2 more
- (no CPE)range: >= 8.0.0, < 8.7.49
- (no CPE)range: >= 10.0.0, < 10.4.33
- (no CPE)range: >= 8.0.0, < 8.7.49
Patches
11302e8856582[SECURITY] Prohibit TypoScript in form yaml files
4 files changed · +254 −10
typo3/sysext/form/Classes/Mvc/Configuration/ConfigurationManager.php+8 −7 modified@@ -122,17 +122,18 @@ protected function overrideConfigurationByTypoScript(array $yamlSettings, string { $typoScript = parent::getConfiguration(self::CONFIGURATION_TYPE_SETTINGS, $extensionName); if (is_array($typoScript['yamlSettingsOverrides'] ?? null) && !empty($typoScript['yamlSettingsOverrides'])) { - ArrayUtility::mergeRecursiveWithOverrule( - $yamlSettings, - $typoScript['yamlSettingsOverrides'] - ); - + $yamlSettingsOverrides = $typoScript['yamlSettingsOverrides']; if (($GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface && ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isFrontend() ) { - $yamlSettings = GeneralUtility::makeInstance(TypoScriptService::class) - ->resolvePossibleTypoScriptConfiguration($yamlSettings); + $yamlSettingsOverrides = GeneralUtility::makeInstance(TypoScriptService::class) + ->resolvePossibleTypoScriptConfiguration($yamlSettingsOverrides); } + + ArrayUtility::mergeRecursiveWithOverrule( + $yamlSettings, + $yamlSettingsOverrides + ); } return $yamlSettings; }
typo3/sysext/form/Classes/Mvc/Persistence/FormPersistenceManager.php+4 −3 modified@@ -626,12 +626,13 @@ public function isAllowedPersistencePath(string $persistencePath): bool protected function overrideByTypoScriptSettings(array $formDefinition): array { if (!empty($this->typoScriptSettings['formDefinitionOverrides'][$formDefinition['identifier']] ?? null)) { + $formDefinitionOverrides = GeneralUtility::makeInstance(TypoScriptService::class) + ->resolvePossibleTypoScriptConfiguration($this->typoScriptSettings['formDefinitionOverrides'][$formDefinition['identifier']]); + ArrayUtility::mergeRecursiveWithOverrule( $formDefinition, - $this->typoScriptSettings['formDefinitionOverrides'][$formDefinition['identifier']] + $formDefinitionOverrides ); - $formDefinition = GeneralUtility::makeInstance(TypoScriptService::class) - ->resolvePossibleTypoScriptConfiguration($formDefinition); } return $formDefinition;
typo3/sysext/form/Tests/Unit/Mvc/Configuration/ConfigurationManagerTest.php+144 −0 added@@ -0,0 +1,144 @@ +<?php + +declare(strict_types=1); + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +namespace TYPO3\CMS\Form\Tests\Unit\Mvc\Configuration; + +use TYPO3\CMS\Core\Core\SystemEnvironmentBuilder; +use TYPO3\CMS\Core\Http\ServerRequest; +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\Configuration\FrontendConfigurationManager; +use TYPO3\CMS\Form\Mvc\Configuration\ConfigurationManager; +use TYPO3\CMS\Form\Mvc\Configuration\ConfigurationManagerInterface; +use TYPO3\CMS\Form\Mvc\Configuration\TypoScriptService; +use TYPO3\TestingFramework\Core\Unit\UnitTestCase; + +class ConfigurationManagerTest extends UnitTestCase +{ + protected bool $resetSingletonInstances = true; + + public function tearDown(): void + { + unset($GLOBALS['TYPO3_REQUEST']); + parent::tearDown(); + } + + /** + * @test + */ + public function getConfigurationDoesNotEvaluateTypoScriptLookalikeInstructionsFromYamlSettingsInFrontendContext(): void + { + $yamlSettings = [ + 'prototypes' => [ + 'standard' => [ + 'formElementsDefinition' => [ + 'Form' => [ + 'renderingOptions' => [ + 'submitButtonLabel' => 'Foo', + 'templateVariant' => 'version1', + 'addQueryString' => [ + 'value' => 'Baz', + '_typoScriptNodeValue' => 'TEXT', + ], + ], + ], + ], + ], + ], + ]; + + $formTypoScript = [ + 'settings' => [ + 'yamlSettingsOverrides' => [ + 'prototypes' => [ + 'standard' => [ + 'formElementsDefinition' => [ + 'Form' => [ + 'renderingOptions' => [ + 'submitButtonLabel' => [ + 'value' => 'Bar', + '_typoScriptNodeValue' => 'TEXT', + ], + ], + ], + ], + ], + ], + ], + ], + ]; + + $evaluatedFormTypoScript = [ + 'prototypes' => [ + 'standard' => [ + 'formElementsDefinition' => [ + 'Form' => [ + 'renderingOptions' => [ + 'submitButtonLabel' => 'Bar', + ], + ], + ], + ], + ], + ]; + + $expected = [ + 'prototypes' => [ + 'standard' => [ + 'formElementsDefinition' => [ + 'Form' => [ + 'renderingOptions' => [ + 'submitButtonLabel' => 'Bar', + 'templateVariant' => 'version1', + 'addQueryString' => [ + 'value' => 'Baz', + '_typoScriptNodeValue' => 'TEXT', + ], + ], + ], + ], + ], + ], + ]; + + $configurationManagerMock = $this->getAccessibleMock(ConfigurationManager::class, [ + 'getTypoScriptSettings', + 'getYamlSettingsFromCache', + ], [], '', false); + $configurationManagerMock->method('getYamlSettingsFromCache')->with(self::anything())->willReturn($yamlSettings); + + $serverRequest = (new ServerRequest())->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_FE); + $GLOBALS['TYPO3_REQUEST'] = $serverRequest; + + $typoScriptServiceMock = $this->createMock(TypoScriptService::class); + $typoScriptServiceMock + ->method('resolvePossibleTypoScriptConfiguration') + ->with($formTypoScript['settings']['yamlSettingsOverrides']) + ->willReturn($evaluatedFormTypoScript); + GeneralUtility::addInstance(TypoScriptService::class, $typoScriptServiceMock); + + $frontendConfigurationManager = $this->createMock(FrontendConfigurationManager::class); + $frontendConfigurationManager + ->method('getConfiguration') + ->with('form', null) + ->willReturn($formTypoScript); + + $configurationManagerMock->_set('concreteConfigurationManager', $frontendConfigurationManager); + $configurationManagerMock->method('getTypoScriptSettings')->with(self::anything())->willReturn([]); + + self::assertSame($expected, $configurationManagerMock->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_YAML_SETTINGS, 'form')); + } +}
typo3/sysext/form/Tests/Unit/Mvc/Persistence/FormPersistenceManagerTest.php+98 −0 modified@@ -734,6 +734,104 @@ public function overrideByTypoScriptSettingsReturnsOverriddenConfigurationIfTypo self::assertSame($expected, $mockController->_call('overrideByTypoScriptSettings', $input)); } + /** + * @test + */ + public function overrideByTypoScriptSettingsDoesNotEvaluateTypoScriptLookalikeInstructionsFromYamlSettings(): void + { + $formDefinitionYaml = [ + 'identifier' => 'ext-form-identifier', + 'prototypeName' => 'standard', + 'label' => [ + 'value' => 'Label override', + '_typoScriptNodeValue' => 'TEXT', + ], + 'renderables' => [ + 0 => [ + 'identifier' => 'page-1', + 'type' => 'Page', + 'label' => 'Label', + 'renderables' => [ + 0 => [ + 'identifier' => 'text-1', + 'type' => 'Text', + 'label' => 'Label', + ], + ], + ], + ], + ]; + + $formTypoScript = [ + 'formDefinitionOverrides' => [ + 'ext-form-identifier' => [ + 'renderables' => [ + 0 => [ + 'renderables' => [ + 0 => [ + 'label' => [ + 'value' => 'Label override', + '_typoScriptNodeValue' => 'TEXT', + ], + ], + ], + ], + ], + ], + ], + ]; + + $evaluatedFormTypoScript = [ + 'renderables' => [ + 0 => [ + 'renderables' => [ + 0 => [ + 'label' => 'Label override', + ], + ], + ], + ], + ]; + + $expected = [ + 'identifier' => 'ext-form-identifier', + 'prototypeName' => 'standard', + 'label' => [ + 'value' => 'Label override', + '_typoScriptNodeValue' => 'TEXT', + ], + 'renderables' => [ + 0 => [ + 'identifier' => 'page-1', + 'type' => 'Page', + 'label' => 'Label', + 'renderables' => [ + 0 => [ + 'identifier' => 'text-1', + 'type' => 'Text', + 'label' => 'Label override', + ], + ], + ], + ], + ]; + + $controllerMock = $this->getAccessibleMock(FormPersistenceManager::class, [ + 'dummy', + ], [], '', false); + + $typoScriptServiceMock = $this->createMock(TypoScriptService::class); + $typoScriptServiceMock + ->method('resolvePossibleTypoScriptConfiguration') + ->with($formTypoScript['formDefinitionOverrides']['ext-form-identifier']) + ->willReturn($evaluatedFormTypoScript); + GeneralUtility::addInstance(TypoScriptService::class, $typoScriptServiceMock); + + $controllerMock->_set('typoScriptSettings', $formTypoScript); + + self::assertSame($expected, $controllerMock->_call('overrideByTypoScriptSettings', $formDefinitionYaml)); + } + /** * @test */
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
7- github.com/advisories/GHSA-c5wx-6c2c-f7rmghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2022-23503ghsaADVISORY
- github.com/FriendsOfPHP/security-advisories/blob/master/typo3/cms-core/CVE-2022-23503.yamlghsaWEB
- github.com/FriendsOfPHP/security-advisories/blob/master/typo3/cms/CVE-2022-23503.yamlghsaWEB
- github.com/TYPO3/typo3/commit/1302e88565821f2159e08b5d818d28de17ecc830ghsaWEB
- github.com/TYPO3/typo3/security/advisories/GHSA-c5wx-6c2c-f7rmghsax_refsource_CONFIRMWEB
- typo3.org/security/advisory/typo3-core-sa-2022-015ghsaWEB
News mentions
0No linked articles in our index yet.