VYPR
High severityNVD Advisory· Published Dec 14, 2022· Updated Apr 18, 2025

TYPO3 vulnerable to Arbitrary Code Execution via Form Framework

CVE-2022-23503

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.

PackageAffected versionsPatched versions
typo3/cms-corePackagist
>= 8.0.0, < 8.7.498.7.49
typo3/cms-corePackagist
>= 9.0.0, < 9.5.389.5.38
typo3/cms-corePackagist
>= 10.0.0, < 10.4.3310.4.33
typo3/cms-corePackagist
>= 11.0.0, < 11.5.2011.5.20
typo3/cms-corePackagist
>= 12.0.0, < 12.1.112.1.1
typo3/cmsPackagist
>= 10.0.0, < 10.4.3310.4.33
typo3/cmsPackagist
>= 11.0.0, < 11.5.2011.5.20
typo3/cmsPackagist
>= 12.0.0, < 12.1.112.1.1

Affected products

4

Patches

1
1302e8856582

[SECURITY] Prohibit TypoScript in form yaml files

https://github.com/TYPO3/typo3waldhackerDec 13, 2022via ghsa
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

News mentions

0

No linked articles in our index yet.