diff --git a/CHANGELOG.md b/CHANGELOG.md index d8a680901..d6df8c3f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -### Fixes +### Security +- Applied appropriate javascript and html escaping in mailto plugin to counter injection attacks [#454](https://github.com/smarty-php/smarty/issues/454) + +### Fixed - Fixed use of `rand()` without a parameter in math function [#794](https://github.com/smarty-php/smarty/issues/794) ## [3.1.46] - 2022-08-01 diff --git a/libs/plugins/function.mailto.php b/libs/plugins/function.mailto.php index 8faf696af..5f4cf3a9e 100644 --- a/libs/plugins/function.mailto.php +++ b/libs/plugins/function.mailto.php @@ -48,8 +48,13 @@ */ function smarty_function_mailto($params) { - static $_allowed_encoding = - array('javascript' => true, 'javascript_charcode' => true, 'hex' => true, 'none' => true); + static $_allowed_encoding = array( + 'javascript' => true, + 'javascript_charcode' => true, + 'hex' => true, + 'none' => true + ); + $extra = ''; if (empty($params[ 'address' ])) { trigger_error("mailto: missing 'address' parameter", E_USER_WARNING); @@ -57,11 +62,11 @@ function smarty_function_mailto($params) } else { $address = $params[ 'address' ]; } + $text = $address; + // netscape and mozilla do not decode %40 (@) in BCC field (bug?) // so, don't encode it. - $search = array('%40', '%2C'); - $replace = array('@', ','); $mail_parms = array(); foreach ($params as $var => $value) { switch ($var) { @@ -69,7 +74,7 @@ function smarty_function_mailto($params) case 'bcc': case 'followupto': if (!empty($value)) { - $mail_parms[] = $var . '=' . str_replace($search, $replace, rawurlencode($value)); + $mail_parms[] = $var . '=' . str_replace(array('%40', '%2C'), array('@', ','), rawurlencode($value)); } break; case 'subject': @@ -83,6 +88,7 @@ function smarty_function_mailto($params) default: } } + if ($mail_parms) { $address .= '?' . join('&', $mail_parms); } @@ -94,19 +100,21 @@ function smarty_function_mailto($params) ); return; } + + $string = '' . htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, Smarty::$_CHARSET) . ''; + if ($encode === 'javascript') { - $string = '' . $text . ''; $js_encode = ''; for ($x = 0, $_length = strlen($string); $x < $_length; $x++) { $js_encode .= '%' . bin2hex($string[ $x ]); } return ''; } elseif ($encode === 'javascript_charcode') { - $string = '' . $text . ''; for ($x = 0, $_length = strlen($string); $x < $_length; $x++) { $ord[] = ord($string[ $x ]); } - return ''; + return ''; } elseif ($encode === 'hex') { preg_match('!^(.*)(\?.*)$!', $address, $match); if (!empty($match[ 2 ])) { @@ -129,6 +137,6 @@ function smarty_function_mailto($params) return '' . $text_encode . ''; } else { // no encoding - return '' . $text . ''; + return $string; } } diff --git a/tests/UnitTests/TemplateSource/TagTests/PluginFunction/PluginFunctionMailtoTest.php b/tests/UnitTests/TemplateSource/TagTests/PluginFunction/PluginFunctionMailtoTest.php index 014a25e14..e84e85bc4 100644 --- a/tests/UnitTests/TemplateSource/TagTests/PluginFunction/PluginFunctionMailtoTest.php +++ b/tests/UnitTests/TemplateSource/TagTests/PluginFunction/PluginFunctionMailtoTest.php @@ -150,7 +150,7 @@ public function testExtraWithoutMbstring() public function testUmlauts() { - $result = 'me+smtpext@example.com'; + $result = 'me+smtpext@example.com'; $tpl = $this->smarty->createTemplate('eval:{mailto address="me+smtpext@example.com" cc="you@example.com,they@example.com" subject="hällo wörld"}'); $this->assertEquals(str_replace("\r", '', $result), $this->smarty->fetch($tpl)); } @@ -158,9 +158,26 @@ public function testUmlauts() public function testUmlautsWithoutMbstring() { Smarty::$_MBSTRING = false; - $result = 'me+smtpext@example.com'; + $result = 'me+smtpext@example.com'; $tpl = $this->smarty->createTemplate('eval:{mailto address="me+smtpext@example.com" cc="you@example.com,they@example.com" subject="hällo wörld"}'); $this->assertEquals(str_replace("\r", '', $result), $this->smarty->fetch($tpl)); Smarty::$_MBSTRING = true; } + + public function testJavascriptChars() + { + $result = ''; + $this->smarty->assign('address', 'me@example.com">me@example.com\'); alert("injection"); //'); + $tpl = $this->smarty->createTemplate('eval:{mailto address=$address encode=javascript}'); + $this->assertEquals(str_replace("\r", '', $result), $this->smarty->fetch($tpl)); + } + + public function testHtmlChars() + { + $result = 'me@example.com"><h1>'; + $this->smarty->assign('address', 'me@example.com">

'); + $tpl = $this->smarty->createTemplate('eval:{mailto address=$address extra=\'class="email"\'}'); + $this->assertEquals(str_replace("\r", '', $result), $this->smarty->fetch($tpl)); + } + }