From 4bb6919a96ef42eb0c048bc5ae4548bda7e7ddcb Mon Sep 17 00:00:00 2001 From: Michael M Slusarz Date: Wed, 21 Jul 2010 18:08:22 -0600 Subject: [PATCH] Convert XSS filter to use DOM/XML parsing. This frees us from having to worry about malformed HTML and instead directly filter the HTML input by removing specific tags and/or attributes. --- framework/Mime/lib/Horde/Mime/Viewer/Html.php | 2 +- .../lib/Horde/Text/Filter/Html2text.php | 2 + .../Text_Filter/lib/Horde/Text/Filter/Xss.php | 417 ++++++++------------- framework/Text_Filter/package.xml | 3 +- .../Text_Filter/test/Horde/Text/Filter/xss.phpt | 238 +++++------- imp/lib/Compose.php | 2 +- 6 files changed, 265 insertions(+), 399 deletions(-) diff --git a/framework/Mime/lib/Horde/Mime/Viewer/Html.php b/framework/Mime/lib/Horde/Mime/Viewer/Html.php index 4509ef16f..00662fda8 100644 --- a/framework/Mime/lib/Horde/Mime/Viewer/Html.php +++ b/framework/Mime/lib/Horde/Mime/Viewer/Html.php @@ -142,8 +142,8 @@ class Horde_Mime_Viewer_Html extends Horde_Mime_Viewer_Driver 'charset' => isset($options['charset']) ? $options['charset'] : $this->_mimepart->getCharset() ), array( - 'body_only' => !empty($options['inline']), 'noprefetch' => !empty($options['noprefetch']), + 'return_document' => empty($options['inline']), 'strip_styles' => $strip_styles, 'strip_style_attributes' => $strip_style_attributes ) diff --git a/framework/Text_Filter/lib/Horde/Text/Filter/Html2text.php b/framework/Text_Filter/lib/Horde/Text/Filter/Html2text.php index f3591ebb2..29c086567 100644 --- a/framework/Text_Filter/lib/Horde/Text/Filter/Html2text.php +++ b/framework/Text_Filter/lib/Horde/Text/Filter/Html2text.php @@ -6,6 +6,8 @@ *
  * charset - (string) The charset to use for html_entity_decode() calls.
  * width - (integer) The wrapping width. Set to 0 to not wrap.
+ * charset - (string) The charset of the text.
+ * width - (integer) The wrapping width.
  * 
* * Copyright 2004-2010 The Horde Project (http://www.horde.org/) diff --git a/framework/Text_Filter/lib/Horde/Text/Filter/Xss.php b/framework/Text_Filter/lib/Horde/Text/Filter/Xss.php index a37e5ba20..0e48997a1 100644 --- a/framework/Text_Filter/lib/Horde/Text/Filter/Xss.php +++ b/framework/Text_Filter/lib/Horde/Text/Filter/Xss.php @@ -1,25 +1,23 @@ - * 'body_only' - (boolean) Only scan within the HTML body tags? - * DEFAULT: true + * 'charset' - (string) The charset of the text. + * DEFAULT: UTF-8 * 'noprefetch' - (boolean) Disable DNS pre-fetching? See: * https://developer.mozilla.org/En/Controlling_DNS_prefetching * DEFAULT: false - * 'replace' - (string) The string to replace filtered tags with. - * DEFAULT: 'XSSCleaned' + * 'return_document' - (string) If true, returns a full HTML representation of + * the document. + * DEFAULT: false (returns the contents contained inside + * the BODY tag) * 'strip_styles' - (boolean) Strip style tags? * DEFAULT: true - * 'strip_style_attributes' - (boolean) Strip style attributes in all HTML - * tags? + * 'strip_style_attributes' - (boolean) Strip style attributes in all tags? * DEFAULT: true * * @@ -29,6 +27,7 @@ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. * * @author Jan Schneider + * @author Michael Slusarz * @category Horde * @license http://www.fsf.org/copyleft/lgpl.html LGPL * @package Text_Filter @@ -41,237 +40,47 @@ class Horde_Text_Filter_Xss extends Horde_Text_Filter_Base * @var array */ protected $_params = array( - 'body_only' => true, + 'charset' => 'UTF-8', 'noprefetch' => false, - 'replace' => 'XSSCleaned', + 'return_document' => false, 'strip_styles' => true, 'strip_style_attributes' => true ); /** - * Stored CDATA information. - * - * @var string - */ - protected $_cdata = array(); - - /** - * CDATA count. - * - * @var integer - */ - protected $_cdatacount = 0; - - /** * Returns a hash with replace patterns. * * @return array Patterns hash. */ public function getPatterns() { - $patterns = array(); - - /* Remove all control characters. */ - $patterns['/[\x00-\x08\x0e-\x1f]/'] = ''; - - /* Removes HTML comments (including some scripts & styles). */ - if ($this->_params['strip_styles']) { - $patterns['//s'] = ''; - } - - /* Change space entities to space characters. */ - $patterns['/&#(?:x0*20|0*32);?/i'] = ' '; - - /* If we have a semicolon, it is deterministically detectable and - * fixable, without introducing collateral damage. */ - $patterns['/&#x?0*(?:[9A-D]|1[0-3]);/i'] = ' '; - - /* Hex numbers (usually having an x prefix) are also deterministic, - * even if we don't have the semi. Note that some browsers will treat - * &#a or �a as a hex number even without the x prefix; hence /x?/ - * which will cover those cases in this rule. */ - $patterns['/&#x?0*[9A-D]([^0-9A-F]|$)/i'] = ' \\1'; - - /* Decimal numbers without trailing semicolons. The problem is that - * some browsers will interpret a as "\na", some as "Ċ" so we - * have to clean the to be safe for the "\na" case at the expense - * of mangling a valid entity in other cases. (Solution for valid HTML - * authors: always use the semicolon.) */ - $patterns['/�*(?:9|1[0-3])([^0-9]|$)/i'] = ' \\1'; - - /* Remove overly long numeric entities. */ - $patterns['/&#x?0*[0-9A-F]{6,};?/i'] = ' '; - - /* Remove everything outside of and including the and - * tags. */ - if ($this->_params['body_only']) { - $patterns['/^.*<(?:body|html)[^>]*>/si'] = ''; - $patterns['/<\/(?:body|html)>.*$/si'] = ''; - } - - /* Get all attribute="javascript:foo()" tags. This is essentially the - * regex /(=|url\()("?)[^>]*script:/ but expanded to catch camouflage - * with spaces and entities. */ - $preg = '/((=|�*61;?|�*3D;?)|' . - '((u|�*85;?|�*55;?|�*117;?|�*75;?|\\\\0*75)\s*' . - '(r|�*82;?|�*52;?|�*114;?|�*72;?|\\\\0*72)\s*' . - '(l|�*76;?|�*4c;?|�*108;?|�*6c;?|\\\\0*6c)\s*' . - '(\(|\\\\0*28)))\s*' . - '(\'|�*34;?|�*22;?|"|�*39;?|�*27;?)?' . - '[^>]*\s*' . - '(s|�*83;?|�*53;?|�*115;?|�*73;?|\\\\0*73)\s*' . - '(c|�*67;?|�*43;?|�*99;?|�*63;?|\\\\0*63)\s*' . - '(r|�*82;?|�*52;?|�*114;?|�*72;?|\\\\0*72)\s*' . - '(i|�*73;?|�*49;?|�*105;?|�*69;?|\\\\0*69)\s*' . - '(p|�*80;?|�*50;?|�*112;?|�*70;?|\\\\0*70)\s*' . - '(t|�*84;?|�*54;?|�*116;?|�*74;?|\\\\0*74)\s*' . - '(:|�*58;?|�*3a;?|\\\\0*3a)/i'; - $patterns[$preg] = '\1\8' . $this->_params['replace']; - - /* Get all on="bar()". NEVER allow these. */ - $patterns['/([\s"\'\/]+' . - '(o|�*79;?|�*4f;?|�*111;?|�*6f;?)' . - '(n|�*78;?|�*4e;?|�*110;?|�*6e;?)' . - '\w+)[^=a-z0-9"\'>]*=/i'] = '\1' . $this->_params['replace'] . '='; - - /* Remove all scripts since they might introduce garbage if they are - * not quoted properly. */ - $patterns['|]*>.*?|is'] = '<' . $this->_params['replace'] . '_script />'; - - /* Get all tags that might cause trouble - , , - * , etc. Meta refreshes and iframes, too. */ - $malicious = array( - '/<([^>a-z]*)' . - '(?:s|�*83;?|�*53;?|�*115;?|�*73;?)\s*' . - '(?:c|�*67;?|�*43;?|�*99;?|�*63;?)\s*' . - '(?:r|�*82;?|�*52;?|�*114;?|�*72;?)\s*' . - '(?:i|�*73;?|�*49;?|�*105;?|�*69;?)\s*' . - '(?:p|�*80;?|�*50;?|�*112;?|�*70;?)\s*' . - '(?:t|�*84;?|�*54;?|�*116;?|�*74;?)/i', - - '/<([^>a-z]*)' . - '(?:e|�*69;?|�*45;?|�*101;?|�*65;?)\s*' . - '(?:m|�*77;?|�*4d;?|�*109;?|�*6d;?)\s*' . - '(?:b|�*66;?|�*42;?|�*98;?|�*62;?)\s*' . - '(?:e|�*69;?|�*45;?|�*101;?|�*65;?)\s*' . - '(?:d|�*68;?|�*44;?|�*100;?|�*64;?)/i', - - '/<([^>a-z]*)' . - '(?:x|�*88;?|�*58;?|�*120;?|�*78;?)\s*' . - '(?:m|�*77;?|�*4d;?|�*109;?|�*6d;?)\s*' . - '(?:l|�*76;?|�*4c;?|�*108;?|�*6c;?)/i', - - '/<([^>a-z]*)\?([^>a-z]*)' . - '(?:i|�*73;?|�*49;?|�*105;?|�*69;?)\s*' . - '(?:m|�*77;?|�*4d;?|�*109;?|�*6d;?)\s*' . - '(?:p|�*80;?|�*50;?|�*112;?|�*70;?)\s*' . - '(?:o|�*79;?|�*4f;?|�*111;?|�*6f;?)\s*' . - '(?:r|�*82;?|�*52;?|�*114;?|�*72;?)\s*' . - '(?:t|�*84;?|�*54;?|�*116;?|�*74;?)/i', - - '/<([^>a-z]*)' . - '(?:m|�*77;?|�*4d;?|�*109;?|�*6d;?)\s*' . - '(?:e|�*69;?|�*45;?|�*101;?|�*65;?)\s*' . - '(?:t|�*84;?|�*54;?|�*116;?|�*74;?)\s*' . - '(?:a|�*65;?|�*41;?|�*97;?|�*61;?)/i', - - '/<([^>a-z]*)' . - '(?:j|�*74;?|�*4a;?|�*106;?|�*6a;?)\s*' . - '(?:a|�*65;?|�*41;?|�*97;?|�*61;?)\s*' . - '(?:v|�*86;?|�*56;?|�*118;?|�*76;?)\s*' . - '(?:a|�*65;?|�*41;?|�*97;?|�*61;?)/i', - - '/<([^>a-z]*)' . - '(?:o|�*79;?|�*4f;?|�*111;?|�*6f;?)\s*' . - '(?:b|�*66;?|�*42;?|�*98;?|�*62;?)\s*' . - '(?:j|�*74;?|�*4a;?|�*106;?|�*6a;?)\s*' . - '(?:e|�*69;?|�*45;?|�*101;?|�*65;?)\s*' . - '(?:c|�*67;?|�*43;?|�*99;?|�*63;?)\s*' . - '(?:t|�*84;?|�*54;?|�*116;?|�*74;?)/i', - - '/<([^>a-z]*)' . - '(?:a|�*65;?|�*41;?|�*97;?|�*61;?)\s*' . - '(?:p|�*80;?|�*50;?|�*112;?|�*70;?)\s*' . - '(?:p|�*80;?|�*50;?|�*112;?|�*70;?)\s*' . - '(?:l|�*76;?|�*4c;?|�*108;?|�*6c;?)\s*' . - '(?:e|�*69;?|�*45;?|�*101;?|�*65;?)\s*' . - '(?:t|�*84;?|�*54;?|�*116;?|�*74;?)/i', - - '/<([^>a-z]*)' . - '(?:l|�*76;?|�*4c;?|�*108;?|�*6c;?)\s*' . - '(?:a|�*65;?|�*41;?|�*97;?|�*61;?)\s*' . - '(?:y|�*89;?|�*59;?|�*121;?|�*79;?)\s*' . - '(?:e|�*69;?|�*45;?|�*101;?|�*65;?)\s*' . - '(?:r|�*82;?|�*52;?|�*114;?|�*72;?)/i', - - '/<([^>a-z]*)' . - '(?:i|�*73;?|�*49;?|�*105;?|�*69;?)?\s*' . - '(?:f|�*70;?|�*46;?|�*102;?|�*66;?)\s*' . - '(?:r|�*82;?|�*52;?|�*114;?|�*72;?)\s*' . - '(?:a|�*65;?|�*41;?|�*97;?|�*61;?)\s*' . - '(?:m|�*77;?|�*4d;?|�*109;?|�*6d;?)\s*' . - '(?:e|�*69;?|�*45;?|�*101;?|�*65;?)/i'); - - foreach ($malicious as $pattern) { - $patterns[$pattern] = '<$1' . $this->_params['replace'] . '_tag'; - } - - /* Comment out style/link tags. */ - if ($this->_params['strip_styles']) { - if ($this->_params['strip_style_attributes']) { - $patterns['/(\s+|([\'"]))style\s*=/i'] = '$2 ' . $this->_params['replace'] . '='; - } - $patterns['|]*>(?:\s*<\!--)*|i'] = '\s*)*|i'] = '-->'; - $patterns['|(]*>)|i'] = ''; - - /* We primarily strip out tags due to styling concerns. - * There is a security issue with HREF tags, but the 'javascript' - * search/replace code sufficiently filters these strings. */ - $patterns['|(]*>)|i'] = ''; - } - - /* A few other matches. */ - $patterns['|<([^>]*)&{.*}([^>]*)>|'] = '<\1&{;}\2>'; - $patterns['|<([^>]*)mocha:([^>]*)>|i'] = '<\1' . $this->_params['replace'] . ':\2>'; - $patterns['/<(([^>]*)|(style[^>]*>[^<]*))binding:((?(3)[^<]*<\/style)[^>]*)>/i'] = '<\1' . $this->_params['replace'] . ':\4>'; - - return array('regexp' => $patterns); - } - - /** - * Executes any code necessary before applying the filter patterns. - * - * @param string $text The text before the filtering. - * - * @return string The modified text. - */ - public function preProcess($text) - { - // As of PHP 5.2, backtrack limits have been set to an unreasonably - // low number. The body check will often times trigger backtrack - // errors so up the backtrack limit if we are doing this match. - if ($this->_params['body_only'] && ini_get('pcre.backtrack_limit')) { - ini_set('pcre.backtrack_limit', 5000000); - } - - // Remove and store CDATA data. - $text = preg_replace_callback('//is', array($this, '_preProcessCallback'), $text); - - return $text; - } - - /** - * Preg callback for preProcess(). - * - * @param array $matches The list of matches. - * - * @return string The replacement text. - */ - protected function _preProcessCallback($matches) - { - $this->_cdata[] = $matches[0]; - return '_cdatacount++ . ' />'; + return array('regexp' => array( + /* Remove all control characters. */ + '/[\x00-\x08\x0e-\x1f]/' => '', + + /* Change space entities to space characters. */ + '/&#(?:x0*20|0*32);?/i' => ' ', + + /* If we have a semicolon, it is deterministically detectable and + * fixable, without introducing collateral damage. */ + '/&#x?0*(?:[9A-D]|1[0-3]);/i' => ' ', + + /* Hex numbers (usually having an x prefix) are also deterministic, + * even if we don't have the semi. Note that some browsers will + * treat &#a or �a as a hex number even without the x prefix; + * hence /x?/ which will cover those cases in this rule. */ + '/&#x?0*[9A-D]([^0-9A-F]|$)/i' => ' \\1', + + /* Decimal numbers without trailing semicolons. The problem is + * that some browsers will interpret a as "\na", some as + * "Ċ" so we have to clean the to be safe for the "\na" + * case at the expense of mangling a valid entity in other cases. + * (Solution for valid HTML authors: always use the semicolon.) */ + '/�*(?:9|1[0-3])([^0-9]|$)/i' => ' \\1', + + /* Remove overly long numeric entities. */ + '/&#x?0*[0-9A-F]{6,};?/i' => ' ' + )); } /** @@ -283,53 +92,139 @@ class Horde_Text_Filter_Xss extends Horde_Text_Filter_Base */ public function postProcess($text) { - /* Strip out data URLs living in an A HREF element (Bug #8715). - * Done here because we need to match more than 1 possible data - * entry per tag. */ - $data_from = '/<((?:a|�*65;?|�*41;?|�*97;?|�*61;?)\b[^>]+?)' . - '(?:h|�*72;?|�*48;?|�*104;?|�*68;?)\s*' . - '(?:r|�*82;?|�*52;?|�*114;?|�*72;?)\s*' . - '(?:e|�*69;?|�*45;?|�*101;?|�*65;?)\s*' . - '(?:f|�*70;?|�*46;?|�*102;?|�*66;?)\s*=' . - '("|\')?\s*data:(?(2)[^"\')>]*|[^\s)>]*)(?(2)\\2)/is'; - $data_to = '<$1'; - do { - $text = preg_replace($data_from, $data_to, $text, -1, $count); - } while ($count); + if (!extension_loaded('dom')) { + return $text; + } + + $old_error = libxml_use_internal_errors(true); + $doc = new DOMDocument(); + $doc->loadHTML($text); + if ($old_error) { + libxml_use_internal_errors(false); + } - ini_restore('pcre.backtrack_limit'); + $this->_node($doc, $doc); - // Restore CDATA data - if ($this->_cdatacount) { - $text = preg_replace_callback('//', array($this, '_postProcessCallback'), $text); - $this->_cdata = array(); - $this->_cdatacount = 0; + if (!$this->_params['return_document']) { + $body = $doc->getElementsByTagName('body')->item(0); } if ($this->_params['noprefetch']) { - if (preg_match('/]*>/si', $text, $matches, PREG_OFFSET_CAPTURE)) { - $end = $matches[0][1] + strlen($matches[0][0]); - $text = substr($text, 0, $end) . - '' . - substr($text, $end); - } else { - $text = '' . $text; + $meta = $doc->createElement('meta'); + $meta->setAttribute('http-equiv', 'x-dns-prefetch-control'); + $meta->setAttribute('value-equiv', 'off'); + + if ($this->_params['return_document']) { + $doc->getElementsByTagName('head')->item(0)->appendChild($meta); + } elseif ($body) { + $body->appendChild($meta); + } + } + + $text = ''; + if ($this->_params['return_document']) { + $text = $doc->saveHTML(); + } elseif ($body && $body->hasChildNodes()) { + foreach ($body->childNodes as $child) { + $text .= $doc->saveXML($child); } } - return $text; + return Horde_String::convertCharset($text, $doc->encoding, $this->_params['charset']); } /** - * Preg callback for preProcess(). + * Process DOM node. * - * @param array $matches The list of matches. + * @param DOMDocument $doc Document node. + * @param DOMElement $node Element node. * - * @return string The replacement text. + * @return string The plaintext representation. */ - protected function _postProcessCallback($matches) + protected function _node($doc, $node) { - return $this->_cdata[$matches[1]]; + if ($node->hasChildNodes()) { + foreach ($node->childNodes as $child) { + if ($child instanceof DOMElement) { + switch (strtolower($child->tagName)) { + case 'a': + /* Strip out data URLs living in an A HREF element + * (Bug #8715). */ + if ($child->hasAttribute('href') && + preg_match("/\s*data:/i", $child->getAttribute('href'))) { + $child->removeAttribute('href'); + } + break; + + case 'applet': + case 'embed': + case 'iframe': + case 'import': + case 'java': + case 'layer': + case 'meta': + case 'object': + case 'script': + case 'xml': + /* Remove all tags that might cause trouble. */ + $node->removeChild($child); + continue 2; + + case 'base': + case 'link': + case 'style': + /* We primarily strip out tags due to styling + * concerns. There is a security issue with HREF tags, + * but the 'javascript' search/replace code + * sufficiently filters these strings. */ + if ($this->_params['strip_styles']) { + $node->removeChild($child); + continue 2; + } + break; + + case 'set': + /* I believe this attack only works on old browsers. + * But makes no sense allowing HTML to try to set + * innerHTML anyway. */ + if ($child->hasAttribute('attributename') && + (strcasecmp($child->getAttribute('attributename'), 'innerHTML') === 0)) { + $node->removeChild($child); + continue 2; + } + } + + $remove = $this->_params['strip_style_attributes'] + ? array('style') + : array(); + + foreach ($child->attributes as $val) { + /* Never allow on="bar()", + * attribute="[mocha|*script]:foo()", or + * attribute="&{...}". */ + if ((stripos(ltrim($val->name), 'on') === 0) || + preg_match("/^\s*(?:mocha:|[^:]+script:|&{)/i", $val->value)) { + $remove[] = $val->name; + } + } + + foreach ($remove as $val) { + $child->removeAttribute($val); + } + + //$patterns['/<(([^>]*)|(style[^>]*>[^<]*))binding:((?(3)[^<]*<\/style)[^>]*)>/i'] = '<\1' . $this->_params['replace'] . ':\4>'; + } elseif ($child instanceof DOMComment) { + /* Remove HTML comments (including some scripts & + * styles). */ + if ($this->_params['strip_styles']) { + $node->removeChild($child); + continue; + } + } + + $this->_node($doc, $child); + } + } } } diff --git a/framework/Text_Filter/package.xml b/framework/Text_Filter/package.xml index 5bfbf5ecc..9b57d63cf 100644 --- a/framework/Text_Filter/package.xml +++ b/framework/Text_Filter/package.xml @@ -37,7 +37,8 @@ http://pear.php.net/dtd/package-2.0.xsd"> beta LGPL - * Remove Horde/Core dependency. + * XSS filter now uses PHP DOM parser to process incoming text. + * Remove Horde/Core dependency. * Add Horde_Text_Filter_Exception::. * Html2text converter now uses XML parser to generate output. * Add ability to define filters to use with preg_replace_callback(). diff --git a/framework/Text_Filter/test/Horde/Text/Filter/xss.phpt b/framework/Text_Filter/test/Horde/Text/Filter/xss.phpt index c63ec0db8..e5cdb4340 100644 --- a/framework/Text_Filter/test/Horde/Text/Filter/xss.phpt +++ b/framework/Text_Filter/test/Horde/Text/Filter/xss.phpt @@ -8,240 +8,208 @@ Horde_Text_Filter_Xss tests require dirname(__FILE__) . '/../../../../lib/Horde/Text/Filter.php'; require dirname(__FILE__) . '/../../../../lib/Horde/Text/Filter/Base.php'; require dirname(__FILE__) . '/../../../../lib/Horde/Text/Filter/Xss.php'; +require dirname(__FILE__) . '/../../../../../Util/lib/Horde/String.php'; +require dirname(__FILE__) . '/../../../../../Util/lib/Horde/Util.php'; foreach (glob(dirname(__FILE__) . '/fixtures/xss*.html') as $file) { - $data = file_get_contents($file); - echo basename($file) . "\n"; - echo Horde_Text_Filter::filter($data, 'xss', array('body_only' => false)); + echo basename($file) . "\n" . + Horde_Text_Filter::filter(file_get_contents($file), 'xss') . + "\n"; } foreach (glob(dirname(__FILE__) . '/fixtures/style_xss*.html') as $file) { - $data = file_get_contents($file); - echo basename($file) . "\n"; - echo Horde_Text_Filter::filter($data, 'xss', array('body_only' => false, 'strip_styles' => false)); + echo basename($file) . "\n" . + Horde_Text_Filter::filter(file_get_contents($file), 'xss', array( + 'strip_styles' => false + )) . + "\n"; } ?> --EXPECT-- xss01.html - + xss02.html - + xss03.html - + xss04.html - + xss05.html - + xss06.html - + xss07.html -"> +"> + xss08.html - + xss09.html - + xss10.html - + xss100.html - + xss11.html - + xss12.html - + xss13.html - + xss14.html - + xss15.html - + xss16.html - + xss17.html - + xss18.html - + xss19.html - + xss20.html - + xss21.html - + xss22.html - + xss23.html -< +

alert("XSS");//

xss24.html - + xss25.html - + xss26.html - xss27.html - + xss29.html - + xss30.html - + xss31.html - + xss32.html - + xss33.html - + xss34.html - + xss35.html - + xss36.html -
+
xss37.html - + xss38.html - + xss39.html - + xss40.html - + xss41.html - + xss42.html - + xss43.html - + xss44.html -
  • XSS +
    • XSS +
    xss45.html - + xss46.html - + xss47.html - + xss48.html - + xss49.html - + xss50.html - + xss51.html - + xss52.html - + xss53.html - +
    xss54.html -
    +
    xss55.html -
    +
    xss56.html -
    +
    xss57.html -
    +
    xss58.html -
    +
    xss59.html - + xss60.html - + xss61.html - + xss62.html -exp/* +

    exp/*

    xss63.html - + xss64.html - + xss65.html - + xss66.html xss67.html - + xss68.html - + xss69.html - + xss70.html - + xss71.html - + xss72.html - - - XSS - +XSS xss73.html -]]> - + xss74.html -<IMG SRC="XSSCleanedalert('XSS')"> - + xss75.html - - + xss76.html - - - - - + + xss77.html - + xss78.html - xss79.html - + xss80.html - + xss81.html - + xss82.html - + xss83.html - + xss84.html - + xss85.html -PT SRC="http://ha.ckers.org/a.js"> +

    PT SRC="http://ha.ckers.org/a.js">

    xss95.html -Click me +Click me xss96.html -Click me +Click me xss97.html - + xss98.html - - - - - - - - - - - - + xss99.html - <"" /> + style_xss01.html - diff --git a/imp/lib/Compose.php b/imp/lib/Compose.php index 31e7231be..5cfc69cc6 100644 --- a/imp/lib/Compose.php +++ b/imp/lib/Compose.php @@ -2462,7 +2462,7 @@ class IMP_Compose } if ($mode == 'html') { - $msg = $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($msg, array('cleanhtml', 'xss'), array(array('body_only' => true), array('body_only' => true, 'strip_styles' => true, 'strip_style_attributes' => false))); + $msg = $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($msg, array('cleanhtml', 'xss'), array(array('body_only' => true), array('strip_styles' => true, 'strip_style_attributes' => false))); } elseif ($type == 'text/html') { $msg = $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($msg, 'html2text'); $type = 'text/plain'; -- 2.11.0