CVE-2021-3603: Inclusion of Functionality from Untrusted Control Sphere (CWE-829)
value: PHPMailer 6.4.1 and earlier contain a vulnerability that can result in untrusted code being called (if such code is injected into the host project's scope by other means). If the $patternselect parameter to validateAddress() is set to 'php' (the default, defined by PHPMailer::$validator), and the global namespace contains a function called php, it will be called in preference to the built-in validator of the same name. Mitigated in PHPMailer 6.5.0 by denying the use of simple strings as validator function names.
CWE description: The product imports, requires, or includes executable functionality (such as a library) from a source that is outside of the intended control sphere.
CVSS v3 base score: 8.1
Published: 2021-06-17T12:15Z
Repository: https://github.com/PHPMailer/PHPMailer
Language: PHP
Files changed: SECURITY.md, src/PHPMailer.php, test/PHPMailerTest.php
Commit date: 2021-06-15 17:37:24 +0200
Commit message: Deny string-based callables altogether

Diff: diff --git a/SECURITY.md b/SECURITY.md
index 8cf18606..cedcd3b0 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -1,10 +1,10 @@
 # Security notices relating to PHPMailer
 
 Please disclose any security issues or vulnerabilities found through [Tidelift's coordinated disclosure system](https://tidelift.com/security) or to the maintainers privately.
 
-PHPMailer 6.4.1 and earlier contain a vulnerability that can result in untrusted code being called (if such code is injected into the host project's scope by other means). If the `$patternselect` parameter to `validateAddress()` is set to `'php'` (the default, defined by `static::$validator`), and the global namespace contains a function called `php`, it will be called in preference to the built-in validator of the same name. This is patched in PHPMailer 6.5.0 by denying the use of callables with the same names as built-in validators. Reported by [Vikrant Singh Chauhan](mailto:vi@hackberry.xyz) via [huntr.dev](https://www.huntr.dev/). Recorded as [CVE-2021-3603](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2021-3603).
+PHPMailer 6.4.1 and earlier contain a vulnerability that can result in untrusted code being called (if such code is injected into the host project's scope by other means). If the `$patternselect` parameter to `validateAddress()` is set to `'php'` (the default, defined by `static::$validator`), and the global namespace contains a function called `php`, it will be called in preference to the built-in validator of the same name. This is patched in PHPMailer 6.5.0 by denying the use of simple strings as validator function names, which is a very minor BC break. Reported by [Vikrant Singh Chauhan](mailto:vi@hackberry.xyz) via [huntr.dev](https://www.huntr.dev/). Recorded as [CVE-2021-3603](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2021-3603).
 
 PHPMailer versions between 6.1.8 and 6.4.0 contain a regression of the earlier CVE-2018-19296 object injection vulnerability as a result of [a fix for Windows UNC paths in 6.1.8](https://github.com/PHPMailer/PHPMailer/commit/e2e07a355ee8ff36aba21d0242c5950c56e4c6f9). Recorded as [CVE-2020-36326](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2020-36326). Reported by Fariskhi Vidyan via Tidelift. 6.4.1 fixes this issue, and also enforces stricter checks for URL schemes in local path contexts.
 
 PHPMailer versions 6.1.5 and earlier contain an output escaping bug that occurs in `Content-Type` and `Content-Disposition` when filenames passed into `addAttachment` and other methods that accept attachment names contain double quote characters, in contravention of RFC822 3.4.1. No specific vulnerability has been found relating to this, but it could allow file attachments to bypass attachment filters that are based on matching filename extensions. Recorded as [CVE-2020-13625](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2020-13625). Reported by Elar Lang of Clarified Security.
 
diff --git a/src/PHPMailer.php b/src/PHPMailer.php
index 83733641..032ef1cf 100644
--- a/src/PHPMailer.php
+++ b/src/PHPMailer.php
@@ -1335,16 +1335,12 @@ class PHPMailer
     public static function validateAddress($address, $patternselect = null)
     {
         if (null === $patternselect) {
             $patternselect = static::$validator;
         }
-        //Don't allow overriding built-in validators with callables
-        if (
-            is_callable($patternselect) &&
-            //It's callable and not a string, or it's a string callable that's not a built-in pattern
-            (!is_string($patternselect) || !in_array(strtolower($patternselect), ['php', 'pcre', 'pcre8', 'html5']))
-        ) {
+        //Don't allow strings as callables, see SECURITY.md and CVE-2021-3603
+        if (is_callable($patternselect) && !is_string($patternselect)) {
             return call_user_func($patternselect, $address);
         }
         //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321
         if (strpos($address, "\n") !== false || strpos($address, "\r") !== false) {
             return false;
diff --git a/test/PHPMailerTest.php b/test/PHPMailerTest.php
index b6c13f06..e6aa4c77 100644
--- a/test/PHPMailerTest.php
+++ b/test/PHPMailerTest.php
@@ -731,17 +731,18 @@ final class PHPMailerTest extends TestCase
         //This is a valid address that FILTER_VALIDATE_EMAIL thinks is invalid
             $this->Mail->addAddress('first.last@example.123'),
             'PHP validator not behaving as expected'
         );
 
-        //Test denying override of built-in validator names
+        //Test denying function name callables as validators
         //See SECURITY.md and CVE-2021-3603
         //If a `php` function defined in validators.php successfully overrides this built-in validator name,
         //this would return false – and we don't want to allow that
         self::assertTrue(PHPMailer::validateAddress('test@example.com', 'php'));
-        //Check a non-matching validator function, which should be permitted, and return false in this case
-        self::assertFalse(PHPMailer::validateAddress('test@example.com', 'phpx'));
+        //Check that a non-existent validator name falls back to a built-in validator
+        //and does not call a global function with that name
+        self::assertTrue(PHPMailer::validateAddress('test@example.com', 'phpx'));
     }
 
     /**
      * Word-wrap an ASCII message.
      */

Vulnerable code: PHPMailer 6.4.1 and earlier contain a vulnerability that can result in untrusted code being called (if such code is injected into the host project's scope by other means). If the `$patternselect` parameter to `validateAddress()` is set to `'php'` (the default, defined by `static::$validator`), and the global namespace contains a function called `php`, it will be called in preference to the built-in validator of the same name. This is patched in PHPMailer 6.5.0 by denying the use of callables with the same names as built-in validators. Reported by [Vikrant Singh Chauhan](mailto:vi@hackberry.xyz) via [huntr.dev](https://www.huntr.dev/). Recorded as [CVE-2021-3603](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2021-3603).
        //Don't allow overriding built-in validators with callables
        if (
            is_callable($patternselect) &&
            //It's callable and not a string, or it's a string callable that's not a built-in pattern
            (!is_string($patternselect) || !in_array(strtolower($patternselect), ['php', 'pcre', 'pcre8', 'html5']))
        ) {
        //Test denying override of built-in validator names
        //Check a non-matching validator function, which should be permitted, and return false in this case
        self::assertFalse(PHPMailer::validateAddress('test@example.com', 'phpx'));
Fixed code: PHPMailer 6.4.1 and earlier contain a vulnerability that can result in untrusted code being called (if such code is injected into the host project's scope by other means). If the `$patternselect` parameter to `validateAddress()` is set to `'php'` (the default, defined by `static::$validator`), and the global namespace contains a function called `php`, it will be called in preference to the built-in validator of the same name. This is patched in PHPMailer 6.5.0 by denying the use of simple strings as validator function names, which is a very minor BC break. Reported by [Vikrant Singh Chauhan](mailto:vi@hackberry.xyz) via [huntr.dev](https://www.huntr.dev/). Recorded as [CVE-2021-3603](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2021-3603).
        //Don't allow strings as callables, see SECURITY.md and CVE-2021-3603
        if (is_callable($patternselect) && !is_string($patternselect)) {
        //Test denying function name callables as validators
        //Check that a non-existent validator name falls back to a built-in validator
        //and does not call a global function with that name
        self::assertTrue(PHPMailer::validateAddress('test@example.com', 'phpx'));