CVE-2023-34099: Improper Check for Unusual or Exceptional Conditions (CWE-754)
value: Shopware is an open source e-commerce software. The mail validation in the registration process had some flaws, so it was possible to construct different mail addresses, that in the end result in the same address, which is shared by multiple accounts. This issue has been addressed in version 5.7.18 and users are advised to update. There are no known workarounds for this vulnerability.
CWE description: The product does not check or incorrectly checks for unusual or exceptional conditions that are not expected to occur frequently during day to day operation of the product.
CVSS v3 base score: 5.3
Published: 2023-06-27T17:15Z
Repository: https://github.com/shopware5/shopware
Language: PHP
Files changed: .phpstan-baseline.neon, engine/Shopware/Components/Validator/EmailValidator.php, tests/Unit/Components/EmailValidatorTest.php
Commit date: 2023-05-10 08:48:25 +0200
Commit message: SW-27102 - changing custom email validation to PHPs FILTER_VALIDATE_EMAIL

Diff: diff --git a/.phpstan-baseline.neon b/.phpstan-baseline.neon
index 62119146ec..1dad7b509d 100644
--- a/.phpstan-baseline.neon
+++ b/.phpstan-baseline.neon
@@ -42923,30 +42923,10 @@ parameters:
 		-
 			message: "#^Method Shopware\\\\Tests\\\\Unit\\\\Components\\\\DispatchFormatHelperTest\\:\\:testFormatNameForRequestOnlyAllowsAlphanumericalCharsAndUnderscore\\(\\) has no return type specified\\.$#"
 			count: 1
 			path: tests/Unit/Components/DispatchFormatHelperTest.php
 
-		-
-			message: "#^Method Shopware\\\\Tests\\\\Unit\\\\Components\\\\EmailValidatorTest\\:\\:getValidEmails\\(\\) has no return type specified\\.$#"
-			count: 1
-			path: tests/Unit/Components/EmailValidatorTest.php
-
-		-
-			message: "#^Method Shopware\\\\Tests\\\\Unit\\\\Components\\\\EmailValidatorTest\\:\\:getinvalidEmails\\(\\) has no return type specified\\.$#"
-			count: 1
-			path: tests/Unit/Components/EmailValidatorTest.php
-
-		-
-			message: "#^Method Shopware\\\\Tests\\\\Unit\\\\Components\\\\EmailValidatorTest\\:\\:testInvalidEmails\\(\\) has no return type specified\\.$#"
-			count: 1
-			path: tests/Unit/Components/EmailValidatorTest.php
-
-		-
-			message: "#^Method Shopware\\\\Tests\\\\Unit\\\\Components\\\\EmailValidatorTest\\:\\:testValidEmails\\(\\) has no return type specified\\.$#"
-			count: 1
-			path: tests/Unit/Components/EmailValidatorTest.php
-
 		-
 			message: "#^Method Shopware\\\\Tests\\\\Unit\\\\Components\\\\Escaper\\\\EscaperTest\\:\\:testItCastsNullToEmptyStrings\\(\\) has no return type specified\\.$#"
 			count: 1
 			path: tests/Unit/Components/Escaper/EscaperTest.php
 
diff --git a/engine/Shopware/Components/Validator/EmailValidator.php b/engine/Shopware/Components/Validator/EmailValidator.php
index e5d610ab40..1eb4c4e388 100644
--- a/engine/Shopware/Components/Validator/EmailValidator.php
+++ b/engine/Shopware/Components/Validator/EmailValidator.php
@@ -32,10 +32,8 @@ class EmailValidator implements EmailValidatorInterface
     /**
      * {@inheritdoc}
      */
     public function isValid($emailAddress)
     {
-        // Inspired by the regex used in symfony/validator
-        // See: https://github.com/symfony/validator/blob/dae70b74fe173461395cfd61a5c5245e05e511f5/Constraints/EmailValidator.php#L72
-        return (bool) preg_match('/^\S+\@\S+\.\S+$/', $emailAddress);
+        return (bool) filter_var($emailAddress, FILTER_VALIDATE_EMAIL);
     }
 }
diff --git a/tests/Unit/Components/EmailValidatorTest.php b/tests/Unit/Components/EmailValidatorTest.php
index 9d0abfacc4..5d10b36310 100644
--- a/tests/Unit/Components/EmailValidatorTest.php
+++ b/tests/Unit/Components/EmailValidatorTest.php
@@ -27,79 +27,83 @@ namespace Shopware\Tests\Unit\Components;
 use PHPUnit\Framework\TestCase;
 use Shopware\Components\Validator\EmailValidator;
 
 class EmailValidatorTest extends TestCase
 {
-    /**
-     * @var EmailValidator
-     */
-    private $SUT;
+    private EmailValidator $SUT;
 
     protected function setUp(): void
     {
         $this->SUT = new EmailValidator();
     }
 
-    public function getValidEmails()
+    /**
+     * @return array<string, array<int, string>>
+     */
+    public function getValidEmails(): array
     {
         return [
             // old domains
-            ['test@example.de'],
-            ['test@example.com'],
-            ['test@example.org'],
+            'test@example.de' => ['test@example.de'],
+            'test@example.com' => ['test@example.com'],
+            'test@example.org' => ['test@example.org'],
 
             // new released domains
-            ['test@example.berlin'],
-            ['test@example.email'],
-            ['test@example.systems'],
+            'test@example.berlin' => ['test@example.berlin'],
+            'test@example.email' => ['test@example.email'],
+            'test@example.systems' => ['test@example.systems'],
 
             // new non released domains
-            ['test@example.active'],
-            ['test@example.love'],
-            ['test@example.video'],
-            ['test@example.app'],
-            ['test@example.shop'],
+            'test@example.active' => ['test@example.active'],
+            'test@example.love' => ['test@example.love'],
+            'test@example.video' => ['test@example.video'],
+            'test@example.app' => ['test@example.app'],
+            'test@example.shop' => ['test@example.shop'],
 
-            ['disposable.style.email.with+symbol@example.com'],
-            ['other.email-with-dash@example.com'],
-
-            // We will ignore quoted string local parts
-            // this would blow up the simple regex method
-            // array('"much.more unusual"@example.com'),
+            'disposable.style.email.with+symbol@example.com' => ['disposable.style.email.with+symbol@example.com'],
+            'other.email-with-dash@example.com' => ['other.email-with-dash@example.com'],
+            '"much.more.unusual"@example.com' => ['"much.more.unusual"@example.com'],
+            '!#$%&*+-/=?^_`.{|}~@example.com' => ['!#$%&*+-/=?^_`.{|}~@example.com'],
         ];
     }
 
     /**
      * @dataProvider getValidEmails
-     *
-     * @param string $email
      */
-    public function testValidEmails($email)
+    public function testValidEmails(string $email): void
     {
         static::assertTrue($this->SUT->isValid($email));
     }
 
-    public function getinvalidEmails()
+    /**
+     * @return array<string, array<int, string>>
+     */
+    public function getInvalidEmails(): array
     {
         return [
-            ['test'],
-            ['test@.de'],
-            ['@example'],
-            ['@example.de'],
-            ['@.'],
-            [' @foo.de'],
-            ['@foo.'],
-            ['foo@ .de'],
-            ['foo@bar. '],
+            'test' => ['test'],
+            'test@.de' => ['test@.de'],
+            '@example' => ['@example'],
+            '@example.de' => ['@example.de'],
+            '@.' => ['@.'],
+            ' @foo.de' => [' @foo.de'],
+            '@foo.' => ['@foo.'],
+            'foo@ .de' => ['foo@ .de'],
+            'foo@bar. ' => ['foo@bar. '],
+            "testing@example.com'||DBMS_PIPE.RECEIVE_MESSAGE(CHR(98)||CHR(98)||CHR(" => ["testing@example.com'||DBMS_PIPE.RECEIVE_MESSAGE(CHR(98)||CHR(98)||CHR("],
+            "testing@example.com'||''||'" => ["testing@example.com'||''||'"],
+            "testing@example.com'|||'" => ["testing@example.com'|||'"],
+            "testing@example.com'||'" => ["testing@example.com'||'"],
+            'test@example.com|' => ['test@example.com|'],
+            'test@example.com(' => ['test@example.com('],
+            'test@example.com"' => ['test@example.com"'],
         ];
     }
 
     /**
      * @dataProvider getInvalidEmails
-     *
-     * @param string $email
      */
-    public function testInvalidEmails($email)
+    public function testInvalidEmails(string $email): void
     {
         static::assertFalse($this->SUT->isValid($email));
     }
 }

Vulnerable code: 		-
			message: "#^Method Shopware\\\\Tests\\\\Unit\\\\Components\\\\EmailValidatorTest\\:\\:getValidEmails\\(\\) has no return type specified\\.$#"
			count: 1
			path: tests/Unit/Components/EmailValidatorTest.php

		-
			message: "#^Method Shopware\\\\Tests\\\\Unit\\\\Components\\\\EmailValidatorTest\\:\\:getinvalidEmails\\(\\) has no return type specified\\.$#"
			count: 1
			path: tests/Unit/Components/EmailValidatorTest.php

		-
			message: "#^Method Shopware\\\\Tests\\\\Unit\\\\Components\\\\EmailValidatorTest\\:\\:testInvalidEmails\\(\\) has no return type specified\\.$#"
			count: 1
			path: tests/Unit/Components/EmailValidatorTest.php

		-
			message: "#^Method Shopware\\\\Tests\\\\Unit\\\\Components\\\\EmailValidatorTest\\:\\:testValidEmails\\(\\) has no return type specified\\.$#"
			count: 1
			path: tests/Unit/Components/EmailValidatorTest.php

        // Inspired by the regex used in symfony/validator
        // See: https://github.com/symfony/validator/blob/dae70b74fe173461395cfd61a5c5245e05e511f5/Constraints/EmailValidator.php#L72
        return (bool) preg_match('/^\S+\@\S+\.\S+$/', $emailAddress);
    /**
     * @var EmailValidator
     */
    private $SUT;
    public function getValidEmails()
            ['test@example.de'],
            ['test@example.com'],
            ['test@example.org'],
            ['test@example.berlin'],
            ['test@example.email'],
            ['test@example.systems'],
            ['test@example.active'],
            ['test@example.love'],
            ['test@example.video'],
            ['test@example.app'],
            ['test@example.shop'],
            ['disposable.style.email.with+symbol@example.com'],
            ['other.email-with-dash@example.com'],

            // We will ignore quoted string local parts
            // this would blow up the simple regex method
            // array('"much.more unusual"@example.com'),
     *
     * @param string $email
    public function testValidEmails($email)
    public function getinvalidEmails()
            ['test'],
            ['test@.de'],
            ['@example'],
            ['@example.de'],
            ['@.'],
            [' @foo.de'],
            ['@foo.'],
            ['foo@ .de'],
            ['foo@bar. '],
     *
     * @param string $email
    public function testInvalidEmails($email)
Fixed code:         return (bool) filter_var($emailAddress, FILTER_VALIDATE_EMAIL);
    private EmailValidator $SUT;
    /**
     * @return array<string, array<int, string>>
     */
    public function getValidEmails(): array
            'test@example.de' => ['test@example.de'],
            'test@example.com' => ['test@example.com'],
            'test@example.org' => ['test@example.org'],
            'test@example.berlin' => ['test@example.berlin'],
            'test@example.email' => ['test@example.email'],
            'test@example.systems' => ['test@example.systems'],
            'test@example.active' => ['test@example.active'],
            'test@example.love' => ['test@example.love'],
            'test@example.video' => ['test@example.video'],
            'test@example.app' => ['test@example.app'],
            'test@example.shop' => ['test@example.shop'],
            'disposable.style.email.with+symbol@example.com' => ['disposable.style.email.with+symbol@example.com'],
            'other.email-with-dash@example.com' => ['other.email-with-dash@example.com'],
            '"much.more.unusual"@example.com' => ['"much.more.unusual"@example.com'],
            '!#$%&*+-/=?^_`.{|}~@example.com' => ['!#$%&*+-/=?^_`.{|}~@example.com'],
    public function testValidEmails(string $email): void
    /**
     * @return array<string, array<int, string>>
     */
    public function getInvalidEmails(): array
            'test' => ['test'],
            'test@.de' => ['test@.de'],
            '@example' => ['@example'],
            '@example.de' => ['@example.de'],
            '@.' => ['@.'],
            ' @foo.de' => [' @foo.de'],
            '@foo.' => ['@foo.'],
            'foo@ .de' => ['foo@ .de'],
            'foo@bar. ' => ['foo@bar. '],
            "testing@example.com'||DBMS_PIPE.RECEIVE_MESSAGE(CHR(98)||CHR(98)||CHR(" => ["testing@example.com'||DBMS_PIPE.RECEIVE_MESSAGE(CHR(98)||CHR(98)||CHR("],
            "testing@example.com'||''||'" => ["testing@example.com'||''||'"],
            "testing@example.com'|||'" => ["testing@example.com'|||'"],
            "testing@example.com'||'" => ["testing@example.com'||'"],
            'test@example.com|' => ['test@example.com|'],
            'test@example.com(' => ['test@example.com('],
            'test@example.com"' => ['test@example.com"'],
    public function testInvalidEmails(string $email): void