VYPR
Moderate severityNVD Advisory· Published Aug 4, 2023· Updated Oct 3, 2024

Sulu Observable Response Discrepancy on Admin Login

CVE-2023-39343

Description

Sulu is an open-source PHP content management system based on the Symfony framework. It allows over the Admin Login form to detect which user (username, email) exists and which one do not exist. Sulu Installation not using the old Symfony 5.4 security System and previous version are not impacted by this Security issue. The vulnerability has been patched in version 2.5.10.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
sulu/suluPackagist
>= 2.5.0, < 2.5.102.5.10

Affected products

1

Patches

1
5f6c98ba030b

Merge pull request from GHSA-wmwf-49vv-p3mr

https://github.com/sulu/suluAlexander SchranzAug 3, 2023via ghsa
5 files changed · +95 38
  • config/packages/security.yaml+2 3 modified
    @@ -20,14 +20,13 @@ security:
             - { path: ^/admin/reset, roles: PUBLIC_ACCESS }
             - { path: ^/admin/security/reset, roles: PUBLIC_ACCESS }
             - { path: ^/admin/login$, roles: PUBLIC_ACCESS }
    +        - { path: ^/admin/2fa, roles: PUBLIC_ACCESS }
             - { path: ^/admin/_wdt, roles: PUBLIC_ACCESS }
    +        - { path: ^/admin/_profiler, roles: PUBLIC_ACCESS }
             - { path: ^/admin/translations, roles: PUBLIC_ACCESS }
             - { path: ^/admin$, roles: PUBLIC_ACCESS }
             - { path: ^/admin/$, roles: PUBLIC_ACCESS }
             - { path: ^/admin/p/, roles: PUBLIC_ACCESS }
    -        - { path: ^/admin/logout, role: PUBLIC_ACCESS }
    -        - { path: ^/admin/_profiler, role: PUBLIC_ACCESS }
    -        - { path: ^/admin/2fa, role: PUBLIC_ACCESS }
             - { path: ^/admin, roles: ROLE_USER }
     
         firewalls:
    
  • src/Sulu/Bundle/SecurityBundle/Security/AuthenticationHandler.php+1 1 modified
    @@ -104,7 +104,7 @@ public function onAuthenticationFailure(Request $request, AuthenticationExceptio
         {
             if ($request->isXmlHttpRequest()) {
                 // if AJAX login
    -            $array = ['message' => $exception->getMessage()];
    +            $array = ['message' => $exception->getMessageKey()];
                 $response = new JsonResponse($array, 401);
             } else {
                 // if form login
    
  • src/Sulu/Bundle/SecurityBundle/Tests/Application/config/config.yml+10 5 modified
    @@ -8,22 +8,27 @@ security:
         access_control:
             - { path: ^/admin/reset, roles: PUBLIC_ACCESS }
             - { path: ^/admin/security/reset, roles: PUBLIC_ACCESS }
    -        - { path: ^/admin/login, roles: PUBLIC_ACCESS }
    -        - { path: ^/admin/2fa, role: PUBLIC_ACCESS }
    +        - { path: ^/admin/login$, roles: PUBLIC_ACCESS }
    +        - { path: ^/admin/2fa, roles: PUBLIC_ACCESS }
    +        - { path: ^/admin/_wdt, roles: PUBLIC_ACCESS }
    +        - { path: ^/admin/_profiler, roles: PUBLIC_ACCESS }
    +        - { path: ^/admin/translations, roles: PUBLIC_ACCESS }
    +        - { path: ^/admin$, roles: PUBLIC_ACCESS }
    +        - { path: ^/admin/$, roles: PUBLIC_ACCESS }
    +        - { path: ^/admin/p/, roles: PUBLIC_ACCESS }
             - { path: ^/admin, roles: ROLE_USER }
     
         firewalls:
             test:
                 pattern: ^/
                 lazy: true
                 entry_point: sulu_security.authentication_entry_point
    -            form_login:
    +            json_login:
                     check_path: sulu_admin.login_check
                     success_handler: sulu_security.authentication_handler
                     failure_handler: sulu_security.authentication_handler
                 logout:
    -                path: /admin/logout
    -                target: /admin/
    +                path: sulu_admin.logout
                 two_factor:
                     prepare_on_login: true
                     prepare_on_access_denied: true
    
  • src/Sulu/Bundle/SecurityBundle/Tests/Functional/Controller/LoginControllerTest.php+0 29 removed
    @@ -1,29 +0,0 @@
    -<?php
    -
    -/*
    - * This file is part of Sulu.
    - *
    - * (c) Sulu GmbH
    - *
    - * This source file is subject to the MIT license that is bundled
    - * with this source code in the file LICENSE.
    - */
    -
    -namespace Sulu\Bundle\AdminBundle\Tests\Functional\Controller;
    -
    -use Sulu\Bundle\TestBundle\Testing\SuluTestCase;
    -
    -class LoginControllerTest extends SuluTestCase
    -{
    -    public function testFalseLoginRedirect(): void
    -    {
    -        $client = $this->createClient();
    -        $client->request('POST', '/admin/login', [
    -            '_username' => 'FalseUser',
    -            '_password' => 'FalsePassword',
    -        ]);
    -        $response = $client->getResponse();
    -        $this->assertHttpStatusCode(302, $response);
    -        $this->assertSame('/admin/', $response->getTargetUrl());
    -    }
    -}
    
  • src/Sulu/Bundle/SecurityBundle/Tests/Functional/Security/AuthenticationHandlerTest.php+82 0 added
    @@ -0,0 +1,82 @@
    +<?php
    +
    +/*
    + * This file is part of Sulu.
    + *
    + * (c) Sulu GmbH
    + *
    + * This source file is subject to the MIT license that is bundled
    + * with this source code in the file LICENSE.
    + */
    +
    +namespace Sulu\Bundle\SecurityBundle\Tests\Functional\Security;
    +
    +use Sulu\Bundle\TestBundle\Testing\SuluTestCase;
    +
    +class AuthenticationHandlerTest extends SuluTestCase
    +{
    +    public function testLoginFail(): void
    +    {
    +        $client = $this->createClient([], [
    +            'CONTENT_TYPE' => 'application/json',
    +            'HTTP_ACCEPT' => 'application/json',
    +            'HTTP_X-Requested-With' => 'XMLHttpRequest',
    +        ]);
    +
    +        $client->request('POST', '/admin/login', [], [], [], '{"username": "not-existing-user", "password": "wrong"}');
    +
    +        $response = $client->getResponse();
    +        $this->assertHttpStatusCode(401, $response);
    +        $notExistUserContent = $response->getContent();
    +
    +        $this->assertSame('{"message":"Invalid credentials."}', $notExistUserContent);
    +    }
    +
    +    public function testLoginSuccess(): void
    +    {
    +        $client = $this->createClient([], [
    +            'CONTENT_TYPE' => 'application/json',
    +            'HTTP_ACCEPT' => 'application/json',
    +            'HTTP_X-Requested-With' => 'XMLHttpRequest',
    +        ]);
    +
    +        $testUser = $this->getTestUser();
    +
    +        $client->request('POST', '/admin/login', [], [], [], '{"username": "' . $testUser->getUsername() . '", "password": "test"}');
    +
    +        $response = $client->getResponse();
    +        $this->assertHttpStatusCode(200, $response);
    +        $notExistUserContent = $response->getContent();
    +
    +        $this->assertSame(
    +            '{"url":"\/admin\/","username":"test","completed":true,"twoFactorMethods":["trusted_devices"]}',
    +            $notExistUserContent
    +        );
    +    }
    +
    +    public function testLoginFailExistUserHasSameMessageAsNotExist(): void
    +    {
    +        $client = $this->createClient([], [
    +            'CONTENT_TYPE' => 'application/json',
    +            'HTTP_ACCEPT' => 'application/json',
    +            'HTTP_X-Requested-With' => 'XMLHttpRequest',
    +        ]);
    +
    +        $testUser = $this->getTestUser();
    +
    +        $client->request('POST', '/admin/login', [], [], [], '{"username": "not-existing-user", "password": "wrong"}');
    +
    +        $response = $client->getResponse();
    +        $this->assertHttpStatusCode(401, $response);
    +        $notExistUserContent = $response->getContent();
    +
    +        $client->request('POST', '/admin/login', [], [], [], '{"username": "' . $testUser->getUsername() . '", "password": "wrong"}');
    +
    +        $response = $client->getResponse();
    +        $this->assertHttpStatusCode(401, $response);
    +        $existUserContent = $response->getContent();
    +
    +        $this->assertSame($notExistUserContent, $existUserContent);
    +        $this->assertSame('{"message":"Invalid credentials."}', $notExistUserContent);
    +    }
    +}
    

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

6

News mentions

0

No linked articles in our index yet.