CVE-2024-39912 (PHP, published 2024-07-15T20:15Z)
Description: value: web-auth/webauthn-lib is an open source set of PHP libraries and a Symfony bundle to allow developers to integrate that authentication mechanism into their web applications. The ProfileBasedRequestOptionsBuilder method returns allowedCredentials without any credentials if no username was found. When WebAuthn is used as the first or only authentication method, an attacker can enumerate usernames based on the absence of the `allowedCredentials` property in the assertion options response. This allows enumeration of valid or invalid usernames. By knowing which usernames are valid, attackers can focus their efforts on a smaller set of potential targets, increasing the efficiency and likelihood of successful attacks. This issue has been addressed in version 4.9.0 and all users are advised to upgrade. There are no known workarounds for this vulnerability.
Severity: nan (CVSS v3 base score: )
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/web-auth/webauthn-framework
Files changed:
phpstan-baseline.neon
src/symfony/src/Controller/AttestationControllerFactory.php
src/symfony/src/Controller/AttestationRequestController.php
src/symfony/src/CredentialOptionsBuilder/ProfileBasedCreationOptionsBuilder.php
src/symfony/src/CredentialOptionsBuilder/PublicKeyCredentialCreationOptionsBuilder.php
src/symfony/src/DependencyInjection/Configuration.php
src/symfony/src/DependencyInjection/Factory/Security/WebauthnFactory.php
src/symfony/src/DependencyInjection/WebauthnExtension.php
tests/symfony/config/config.yml
tests/symfony/functional/Attestation/AdditionalAuthenticatorTest.php
tests/symfony/functional/PublicKeyCredentialSourceRepository.php
Commit message: Add feature to hide existing credentials

The code changes enable suppressing the existing user credential details to enhance security. This feature introduces a preventive measure against username enumeration exploits by concealing the previously existing credentials. The flag 'hide_existing_credentials' has been added to facilitate this change, defaulted to false. This change is particularly important during the attestation ceremony performed by anonymous users.


Vulnerable code:
		-
			message: "#^Should not use function \"dump\", please change the code\\.$#"
			count: 1
			path: src/symfony/src/CredentialOptionsBuilder/ProfileBasedRequestOptionsBuilder.php

            $failureHandler
            $publicKeyCredentialCreationOptions = $this->extractor->getFromRequest($request, $userEntity);
        PublicKeyCredentialUserEntity $userEntity
        $excludedCredentials = $this->getCredentials($userEntity);
        PublicKeyCredentialUserEntity $userEntity

Fixed code:
		-
			message: "#^Method Webauthn\\\\Bundle\\\\CredentialOptionsBuilder\\\\PublicKeyCredentialCreationOptionsBuilder\\:\\:getFromRequest\\(\\) invoked with 3 parameters, 2 required\\.$#"
			count: 1
			path: src/symfony/src/Controller/AttestationRequestController.php

		-
			message: "#^Cannot access offset 'hide_existing…' on mixed\\.$#"
			count: 1
			path: src/symfony/src/DependencyInjection/WebauthnExtension.php

        bool $hideExistingExcludedCredentials = false
            $failureHandler,
            $hideExistingExcludedCredentials
        private readonly bool $hideExistingExcludedCredentials = false,
            $publicKeyCredentialCreationOptions = $this->extractor->getFromRequest(
                $request,
                $userEntity,
                $this->hideExistingExcludedCredentials
            );
        PublicKeyCredentialUserEntity $userEntity,
        bool $hideExistingExcludedCredentials = false
        $excludedCredentials = $hideExistingExcludedCredentials === true ? [] : $this->getCredentials($userEntity);
        PublicKeyCredentialUserEntity $userEntity,
        /*bool $hideExistingExcludedCredentials = false*/
            ->scalarNode('hide_existing_credentials')
                ->info(
                    'In order to prevent username enumeration, the existing credentials can be hidden. This is highly recommended when the attestation ceremony is performed by anonymous users.'
                )
                ->defaultFalse()
            ->end()
                true,
                    $creationConfig['hide_existing_credentials'] ?? false,
        hide_existing_credentials: true
        static::assertArrayNotHasKey('excludeCredentials', $data); // username enumeration prevention is enabled
        $publicKeyCredentialSource2 = PublicKeyCredentialSource::create(
            base64_decode(
                'Ac8zKrpVWv9UCwxY1FyMqkESz2lV4CNwTk2+Hp19LgKbvh5uQ2/i6AMbTbTz1zcNapCEeiLJPlAAVM4L7AIow6I=',
                true
            ),
            PublicKeyCredentialDescriptor::CREDENTIAL_TYPE_PUBLIC_KEY,
            [],
            AttestationStatement::TYPE_NONE,
            EmptyTrustPath::create(),
            Uuid::fromBinary(base64_decode('AAAAAAAAAAAAAAAAAAAAAA==', true)),
            base64_decode(
                'pQECAyYgASFYIJV56vRrFusoDf9hm3iDmllcxxXzzKyO9WruKw4kWx7zIlgg/nq63l8IMJcIdKDJcXRh9hoz0L+nVwP1Oxil3/oNQYs=',
                true
            ),
            '929fba2f-2361-4bc6-a917-bb76aa14c7f9',
            100
        );
        $this->saveCredentialSource($publicKeyCredentialSource2);