VYPR
High severityNVD Advisory· Published Feb 1, 2022· Updated Apr 23, 2025

CSRF token missing in Symfony

CVE-2022-23601

Description

Symfony is a PHP framework for web and console applications and a set of reusable PHP components. The Symfony form component provides a CSRF protection mechanism by using a random token injected in the form and using the session to store and control the token submitted by the user. When using the FrameworkBundle, this protection can be enabled or disabled with the configuration. If the configuration is not specified, by default, the mechanism is enabled as long as the session is enabled. In a recent change in the way the configuration is loaded, the default behavior has been dropped and, as a result, the CSRF protection is not enabled in form when not explicitly enabled, which makes the application sensible to CSRF attacks. This issue has been resolved in the patch versions listed and users are advised to update. There are no known workarounds for this issue.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
symfony/framework-bundlePackagist
>= 5.3.14, < 5.3.155.3.15
symfony/framework-bundlePackagist
>= 5.4.3, < 5.4.45.4.4
symfony/framework-bundlePackagist
>= 6.0.3, < 6.0.46.0.4

Affected products

1

Patches

1
f0ffb775febd

Enable CSRF in FORM by default

https://github.com/symfony/symfonyJérémy DerusséJan 28, 2022via ghsa
5 files changed · +108 59
  • src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php+66 59 modified
    @@ -311,26 +311,6 @@ public function load(array $configs, ContainerBuilder $container)
                 $this->registerRequestConfiguration($config['request'], $container, $loader);
             }
     
    -        if ($this->isConfigEnabled($container, $config['form'])) {
    -            if (!class_exists(Form::class)) {
    -                throw new LogicException('Form support cannot be enabled as the Form component is not installed. Try running "composer require symfony/form".');
    -            }
    -
    -            $this->formConfigEnabled = true;
    -            $this->registerFormConfiguration($config, $container, $loader);
    -
    -            if (ContainerBuilder::willBeAvailable('symfony/validator', Validation::class, ['symfony/framework-bundle', 'symfony/form'])) {
    -                $config['validation']['enabled'] = true;
    -            } else {
    -                $container->setParameter('validator.translation_domain', 'validators');
    -
    -                $container->removeDefinition('form.type_extension.form.validator');
    -                $container->removeDefinition('form.type_guesser.validator');
    -            }
    -        } else {
    -            $container->removeDefinition('console.command.form_debug');
    -        }
    -
             if ($this->isConfigEnabled($container, $config['assets'])) {
                 if (!class_exists(\Symfony\Component\Asset\Package::class)) {
                     throw new LogicException('Asset support cannot be enabled as the Asset component is not installed. Try running "composer require symfony/asset".');
    @@ -339,39 +319,6 @@ public function load(array $configs, ContainerBuilder $container)
                 $this->registerAssetsConfiguration($config['assets'], $container, $loader);
             }
     
    -        if ($this->messengerConfigEnabled = $this->isConfigEnabled($container, $config['messenger'])) {
    -            $this->registerMessengerConfiguration($config['messenger'], $container, $loader, $config['validation']);
    -        } else {
    -            $container->removeDefinition('console.command.messenger_consume_messages');
    -            $container->removeDefinition('console.command.messenger_debug');
    -            $container->removeDefinition('console.command.messenger_stop_workers');
    -            $container->removeDefinition('console.command.messenger_setup_transports');
    -            $container->removeDefinition('console.command.messenger_failed_messages_retry');
    -            $container->removeDefinition('console.command.messenger_failed_messages_show');
    -            $container->removeDefinition('console.command.messenger_failed_messages_remove');
    -            $container->removeDefinition('cache.messenger.restart_workers_signal');
    -
    -            if ($container->hasDefinition('messenger.transport.amqp.factory') && !class_exists(AmqpTransportFactory::class)) {
    -                if (class_exists(\Symfony\Component\Messenger\Transport\AmqpExt\AmqpTransportFactory::class)) {
    -                    $container->getDefinition('messenger.transport.amqp.factory')
    -                        ->setClass(\Symfony\Component\Messenger\Transport\AmqpExt\AmqpTransportFactory::class)
    -                        ->addTag('messenger.transport_factory');
    -                } else {
    -                    $container->removeDefinition('messenger.transport.amqp.factory');
    -                }
    -            }
    -
    -            if ($container->hasDefinition('messenger.transport.redis.factory') && !class_exists(RedisTransportFactory::class)) {
    -                if (class_exists(\Symfony\Component\Messenger\Transport\RedisExt\RedisTransportFactory::class)) {
    -                    $container->getDefinition('messenger.transport.redis.factory')
    -                        ->setClass(\Symfony\Component\Messenger\Transport\RedisExt\RedisTransportFactory::class)
    -                        ->addTag('messenger.transport_factory');
    -                } else {
    -                    $container->removeDefinition('messenger.transport.redis.factory');
    -                }
    -            }
    -        }
    -
             if ($this->httpClientConfigEnabled = $this->isConfigEnabled($container, $config['http_client'])) {
                 $this->registerHttpClientConfiguration($config['http_client'], $container, $loader, $config['profiler']);
             }
    @@ -380,18 +327,12 @@ public function load(array $configs, ContainerBuilder $container)
                 $this->registerMailerConfiguration($config['mailer'], $container, $loader);
             }
     
    -        if ($this->notifierConfigEnabled = $this->isConfigEnabled($container, $config['notifier'])) {
    -            $this->registerNotifierConfiguration($config['notifier'], $container, $loader);
    -        }
    -
             $propertyInfoEnabled = $this->isConfigEnabled($container, $config['property_info']);
    -        $this->registerValidationConfiguration($config['validation'], $container, $loader, $propertyInfoEnabled);
             $this->registerHttpCacheConfiguration($config['http_cache'], $container, $config['http_method_override']);
             $this->registerEsiConfiguration($config['esi'], $container, $loader);
             $this->registerSsiConfiguration($config['ssi'], $container, $loader);
             $this->registerFragmentsConfiguration($config['fragments'], $container, $loader);
             $this->registerTranslatorConfiguration($config['translator'], $container, $loader, $config['default_locale']);
    -        $this->registerProfilerConfiguration($config['profiler'], $container, $loader);
             $this->registerWorkflowConfiguration($config['workflows'], $container, $loader);
             $this->registerDebugConfiguration($config['php_errors'], $container, $loader);
             $this->registerRouterConfiguration($config['router'], $container, $loader, $config['translator']['enabled_locales'] ?? []);
    @@ -461,6 +402,72 @@ public function load(array $configs, ContainerBuilder $container)
             }
             $this->registerSecurityCsrfConfiguration($config['csrf_protection'], $container, $loader);
     
    +        // form depends on csrf being registered
    +        if ($this->isConfigEnabled($container, $config['form'])) {
    +            if (!class_exists(Form::class)) {
    +                throw new LogicException('Form support cannot be enabled as the Form component is not installed. Try running "composer require symfony/form".');
    +            }
    +
    +            $this->formConfigEnabled = true;
    +            $this->registerFormConfiguration($config, $container, $loader);
    +
    +            if (ContainerBuilder::willBeAvailable('symfony/validator', Validation::class, ['symfony/framework-bundle', 'symfony/form'])) {
    +                $config['validation']['enabled'] = true;
    +            } else {
    +                $container->setParameter('validator.translation_domain', 'validators');
    +
    +                $container->removeDefinition('form.type_extension.form.validator');
    +                $container->removeDefinition('form.type_guesser.validator');
    +            }
    +        } else {
    +            $container->removeDefinition('console.command.form_debug');
    +        }
    +
    +        // validation depends on form, annotations being registered
    +        $this->registerValidationConfiguration($config['validation'], $container, $loader, $propertyInfoEnabled);
    +
    +        // messenger depends on validation being registered
    +        if ($this->messengerConfigEnabled = $this->isConfigEnabled($container, $config['messenger'])) {
    +            $this->registerMessengerConfiguration($config['messenger'], $container, $loader, $config['validation']);
    +        } else {
    +            $container->removeDefinition('console.command.messenger_consume_messages');
    +            $container->removeDefinition('console.command.messenger_debug');
    +            $container->removeDefinition('console.command.messenger_stop_workers');
    +            $container->removeDefinition('console.command.messenger_setup_transports');
    +            $container->removeDefinition('console.command.messenger_failed_messages_retry');
    +            $container->removeDefinition('console.command.messenger_failed_messages_show');
    +            $container->removeDefinition('console.command.messenger_failed_messages_remove');
    +            $container->removeDefinition('cache.messenger.restart_workers_signal');
    +
    +            if ($container->hasDefinition('messenger.transport.amqp.factory') && !class_exists(AmqpTransportFactory::class)) {
    +                if (class_exists(\Symfony\Component\Messenger\Transport\AmqpExt\AmqpTransportFactory::class)) {
    +                    $container->getDefinition('messenger.transport.amqp.factory')
    +                        ->setClass(\Symfony\Component\Messenger\Transport\AmqpExt\AmqpTransportFactory::class)
    +                        ->addTag('messenger.transport_factory');
    +                } else {
    +                    $container->removeDefinition('messenger.transport.amqp.factory');
    +                }
    +            }
    +
    +            if ($container->hasDefinition('messenger.transport.redis.factory') && !class_exists(RedisTransportFactory::class)) {
    +                if (class_exists(\Symfony\Component\Messenger\Transport\RedisExt\RedisTransportFactory::class)) {
    +                    $container->getDefinition('messenger.transport.redis.factory')
    +                        ->setClass(\Symfony\Component\Messenger\Transport\RedisExt\RedisTransportFactory::class)
    +                        ->addTag('messenger.transport_factory');
    +                } else {
    +                    $container->removeDefinition('messenger.transport.redis.factory');
    +                }
    +            }
    +        }
    +
    +        // notifier depends on messenger, mailer being registered
    +        if ($this->notifierConfigEnabled = $this->isConfigEnabled($container, $config['notifier'])) {
    +            $this->registerNotifierConfiguration($config['notifier'], $container, $loader);
    +        }
    +
    +        // profiler depends on form, validation, translation, messenger, mailer, http-client, notifier being registered
    +        $this->registerProfilerConfiguration($config['profiler'], $container, $loader);
    +
             $this->addAnnotatedClassesToCompile([
                 '**\\Controller\\',
                 '**\\Entity\\',
    
  • src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/form_default_csrf.php+11 0 added
    @@ -0,0 +1,11 @@
    +<?php
    +
    +$container->loadFromExtension('framework', [
    +    'form' => [
    +        'legacy_error_messages' => false,
    +    ],
    +    'session' => [
    +        'storage_factory_id' => 'session.storage.factory.native',
    +        'handler_id' => null,
    +    ],
    +]);
    
  • src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/form_default_csrf.xml+13 0 added
    @@ -0,0 +1,13 @@
    +<?xml version="1.0" ?>
    +
    +<container xmlns="http://symfony.com/schema/dic/services"
    +    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    +    xmlns:framework="http://symfony.com/schema/dic/symfony"
    +    xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
    +                        http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
    +
    +    <framework:config>
    +        <framework:form enabled="true" legacy-error-messages="false" />
    +        <framework:session storage-factory-id="session.storage.factory.native" handler-id="null"/>
    +    </framework:config>
    +</container>
    
  • src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/form_default_csrf.yml+6 0 added
    @@ -0,0 +1,6 @@
    +framework:
    +    form:
    +        legacy_error_messages: false
    +    session:
    +        storage_factory_id: session.storage.factory.native
    +        handler_id: null
    
  • src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php+12 0 modified
    @@ -159,6 +159,18 @@ public function testCsrfProtectionForFormsEnablesCsrfProtectionAutomatically()
             $this->assertTrue($container->hasDefinition('security.csrf.token_manager'));
         }
     
    +    public function testFormsCsrfIsEnabledByDefault()
    +    {
    +        if (class_exists(FullStack::class)) {
    +            $this->markTestSkipped('testing with the FullStack prevents verifying default values');
    +        }
    +        $container = $this->createContainerFromFile('form_default_csrf');
    +
    +        $this->assertTrue($container->hasDefinition('security.csrf.token_manager'));
    +        $this->assertTrue($container->hasParameter('form.type_extension.csrf.enabled'));
    +        $this->assertTrue($container->getParameter('form.type_extension.csrf.enabled'));
    +    }
    +
         public function testHttpMethodOverride()
         {
             $container = $this->createContainerFromFile('full');
    

Vulnerability mechanics

Generated by null/stub 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.