php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Doc Bug #78958 FILTER_VALIDATE_EMAIL fails on a long email address
Submitted: 2019-12-13 11:55 UTC Modified: 2019-12-14 16:03 UTC
From: kaulkwappe dot php-bugs at prvy dot eu Assigned:
Status: Open Package: Filter related
PHP Version: 7.3.11 OS: Debian Buster 10.2
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2019-12-13 11:55 UTC] kaulkwappe dot php-bugs at prvy dot eu
Description:
------------
---
From manual page: https://php.net/filter.filters.validate
---


Test script:
---------------
$email = 'php-announce-sc.123456.abcabcabcabcabcabc-abcabcabc-php=example.com@lists.php.net';
var_dump(filter_var($email, FILTER_VALIDATE_EMAIL));

Expected result:
----------------
Should return validate and return the string.

Actual result:
--------------
Does not validate. Returns
> bool(false)

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-12-13 15:15 UTC] cmb@php.net
-Status: Open +Status: Verified
 [2019-12-13 15:15 UTC] cmb@php.net
Confirmed: <https://3v4l.org/eikec>.
 [2019-12-13 15:26 UTC] requinix@php.net
-Summary: PHP Version 7.3.11-1~deb10u1 +Summary: FILTER_VALIDATE_EMAIL fails on a valid email address
 [2019-12-13 15:42 UTC] requinix@php.net
-Status: Verified +Status: Not a bug
 [2019-12-13 15:42 UTC] requinix@php.net
According to RFC 5321, the local part of an email address (before the @) is limited to 64 characters.
https://tools.ietf.org/html/rfc5321#section-4.5.3.1.1
 [2019-12-13 15:48 UTC] kaulkwappe dot php-bugs at prvy dot eu
Seems then to be a bug of the PHP mailing lists (https://www.php.net/mailing-lists.php) since they return such invalid email addresses.
 [2019-12-13 15:48 UTC] kaulkwappe dot php-bugs at prvy dot eu
-PHP Version: 7.3.12 +PHP Version: 7.3.11
 [2019-12-13 17:52 UTC] cmb@php.net
While the documentation of FILTER_VALIDATE_EMAIL claims it would
validate against the syntax in RFC 822, that has obviously been
changed with the fix for bug #49576.
 [2019-12-13 18:46 UTC] kaulkwappe dot php-bugs at prvy dot eu
I think a strict mode would make sense since developers may want to

a) prevent users from entering a new, not RFC valid email address, but
b) also prevent pseudo false positives from foreign email addresses.

E.g. when an user answers an email the system would check if the recipient email address you entered is valid; however, the replying user cannot influence its RFC validness because it is an foreign email address. Not RFC conform, but still valid. But the same user may not choose a RFC invalid email address if he wants to create an email alias for himself.
 [2019-12-13 19:49 UTC] requinix@php.net
-Summary: FILTER_VALIDATE_EMAIL fails on a valid email address +Summary: FILTER_VALIDATE_EMAIL fails on a long email address -Status: Not a bug +Status: Open -Type: Bug +Type: Documentation Problem
 [2019-12-13 19:49 UTC] requinix@php.net
Maybe NAB is a bit too aggressive a reaction.

The thing with SMTP is that servers do whatever they want. The standards themselves even acknowledge this in a few places. So while 64 octets is supposed to be the maximum, the actual emailing industry will kinda just do whatever it wants.

Some documentation about exactly what rules PHP uses to validate emails (and maybe URLs too?) would be nice. More than just a link to an RFC. A summary of the rules enforced.
But I think the real bug here is with PHP's listserv. exim, I believe.
 [2019-12-14 15:11 UTC] drtechno at mail dot com
looking at the source code:
#define SAFE        "$-_.+"
#define EXTRA       "!*'(),"
#define NATIONAL    "{}|\\^~[]`"
#define PUNCTUATION "<>#%\""
#define RESERVED    ";/?:@&="

void php_filter_email(PHP_INPUT_FILTER_PARAM_DECL)
{

	const unsigned char allowed_list[] = LOWALPHA HIALPHA DIGIT "!#$%&'*+-=?^_`{|}~@.[]";
	filter_map     map;

	filter_map_init(&map);
	filter_map_update(&map, 1, allowed_list);
	filter_map_apply(value, &map);
}

it appears to be not correct.... I would think it would be:

#define SAFE        "$-_.+"
#define EXTRA       "!*'(),"
#define NATIONAL    "{}|\\^~[]`"
#define PUNCTUATION "<>#%\""
#define RESERVED    ";/?:@&="

void php_filter_email(PHP_INPUT_FILTER_PARAM_DECL)
{
	/* Check section 6 of rfc 822 http://www.faqs.org/rfcs/rfc822.html */
	const unsigned char allowed_list[] = LOWALPHA HIALPHA DIGIT "@.";
	filter_map     map;

	filter_map_init(&map);
	filter_map_update(&map, 1, allowed_list);
	filter_map_apply(value, &map);
}
 [2019-12-14 15:21 UTC] drtechno at mail dot com
But I would do a #define EMAIL_ADDR "@." so that the function would look like:
#define SAFE        "$-_.+"
#define EXTRA       "!*'(),"
#define NATIONAL    "{}|\\^~[]`"
#define PUNCTUATION "<>#%\""
#define RESERVED    ";/?:@&="
#define EMAIL_ADDR "@."
void php_filter_email(PHP_INPUT_FILTER_PARAM_DECL)
{const unsigned char allowed_list[] = LOWALPHA HIALPHA DIGIT EMAIL_ADDR;
filter_map map;
filter_map_init(&map);
filter_map_update(&map, 1, allowed_list);
filter_map_apply(value, &map);
}

This file (sanitizing_filters.c),has a lot of extra space characters. They should be removed so white space injection isn't a possibility....
 [2019-12-14 15:28 UTC] drtechno at mail dot com
CORRECTION:
FORGOT THAT UNDERSCORE, AND MINUS SIGN IS USED IN EMAILS


#define EMAIL_ADDR "@._-"
 [2019-12-14 15:45 UTC] drtechno at mail dot com
Keep in mind mail() has a critical flaw: a nested parameter. very bad practice, as the nested parameter can be filled even though the program didn't use it. lets look at mail():
bool mail(	
	string $to, 
	string $subject,
	string $message [, 
	string $additional_headers [, 
	string $additional_parameters ]]
)
$additional_parameters is the weak code and the exploit in the MTA (mail transfer agent)...

When PHP is configured with the second option, calls to the mail() function will result in the execution of the configured MTA program. Although PHP internally applies escapeshellcmd() to the program call which prevents an injection of new shell commands, the 5th argument $additional_parameters in mail() allows the addition of new program arguments to the MTA. Thus, an attacker can append program flags which in some MTA’s enables the creation of a file with user-controlled content.
vilnerable code:
mail("myfriend@example.com", "subject", "message", "", "-f" . $_GET['from']);
The code shown above is prone to a remote command execution that is easily overlooked. The GET parameter from is used unsanitized and allows an attacker to pass additional parameters to the mail program. For example, in sendmail, the parameter -O can be used to reconfigure sendmail options and the parameter -X specifies the location of a log file.
Proof of concept:
example@example.com -OQueueDirectory=/tmp -X/var/www/html/rce.php
The proof of concept will drop a PHP shell in the web directory of the application. This file contains log information that can be tainted with PHP code. Thus, an attacker is able to execute arbitrary PHP code on the web server when accessing the rce.php file.


Another intuitive approach is to use PHP’s email filter in order to ensure that only a valid email address is used in the 5th parameter of mail().
filter_var($email, FILTER_VALIDATE_EMAIL)
However, not all characters that are necessary to exploit the security issue in mail() are forbidden by this filter. It allows the usage of escaped whitespaces nested in double quotes. Due to the nature of the underlying regular expression it is possible to overlap single and double quotes and trick filter_var() into thinking we are inside of double quotes, although mail()s internal escapeshellcmd() thinks we are not.
Toxic code:
'a."'\ -OQueueDirectory=\%0D<?=eval($_GET[c])?>\ -X/var/www/html/"@a.php
For the here given url-encoded input, the filter_var() function returns true and rates the payload as a valid email address. This has a critical impact when using this function as a sole security measure: Similar as in our original attack, our malicious "email address" would cause sendmail to print the following error into our newly generated shell "@a.php in our webroot.

<?=eval($_GET[c])?>\/): No such file or directory

Remember that filter_var() is not appropriate to be used for user-input sanitization and was never designed for such cases, as it is too loose regarding several characters.
 [2019-12-14 16:03 UTC] kaulkwappe dot php-bugs at prvy dot eu
> Remember that filter_var() is not appropriate to be used for
> user-input sanitization and was never designed for such cases,
> as it is too loose regarding several characters.

Thanks for bringing that to mind. I guess following approach would be recommended:


$sanitized = \filter_var($email, FILTER_SANITIZE_EMAIL);

if ($sanitized === $email && \filter_var($email, FILTER_VALIDATE_EMAIL)) {
	return true;
}

return false;
 [2019-12-14 16:12 UTC] drtechno at mail dot com
We should develop application filters, because the current ones are designed for web page formatting, instead of web-applications.
It must be separate from any other functions, including escapeshellcmd()
A small addition of these functions would solve things:

filter_user_text: only a-z,A-Z,0-9, and !@#$%^&*-+_ are passed, "(){}[]';:'<>,. are encoded to html entitites, but anything below ASCII #32 (space character) and anything above ASCII #126 get escaped.
 
PHP Copyright © 2001-2020 The PHP Group
All rights reserved.
Last updated: Wed Apr 08 16:01:25 2020 UTC