CVE-2012-3508: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Cross-site scripting (XSS) vulnerability in program/lib/washtml.php in Roundcube Webmail 0.8.0 allows remote attackers to inject arbitrary web script or HTML by using "javascript:" in an href attribute in the body of an HTML-formatted email.
CWE description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
Published: 2012-08-25T10:29Z
Repository: https://github.com/roundcube/roundcubemail
Language: Other
Files changed: CHANGELOG, program/lib/washtml.php
Commit date: 2012-08-15 10:12:18 +0200
Commit message: Fix XSS issue with href="javascript:" not being removed (#1488613)

Diff: diff --git a/CHANGELOG b/CHANGELOG
index 4e2b22a4..93268064 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,8 +1,9 @@
 CHANGELOG Roundcube Webmail
 ===========================
 
+- Fix XSS issue with href="javascript:" not being removed (#1488613)
 - Fix impossible to create message with empty plain text part (#1488610)
 - Fix stripped apostrophes when replying in plain text to HTML message (#1488606)
 - Fix inactive Save search option after advanced search (#1488607)
 - Fix Remove from group option is active for contact search result (#1488608)
 - Disable autocapitalization in login form on iPad/iPhone (#1488609)
diff --git a/program/lib/washtml.php b/program/lib/washtml.php
index c12315fe..98ae5ed5 100644
--- a/program/lib/washtml.php
+++ b/program/lib/washtml.php
@@ -212,12 +212,15 @@ class washtml
 
     foreach ($node->attributes as $key => $plop) {
       $key = strtolower($key);
       $value = $node->getAttribute($key);
       if (isset($this->_html_attribs[$key]) ||
-         ($key == 'href' && preg_match('!^([a-z][a-z0-9.+-]+:|//|#).+!i', $value)))
+         ($key == 'href' && !preg_match('!^javascript!i', $value)
+           && preg_match('!^([a-z][a-z0-9.+-]+:|//|#).+!i', $value))
+      ) {
         $t .= ' ' . $key . '="' . htmlspecialchars($value, ENT_QUOTES) . '"';
+      }
       else if ($key == 'style' && ($style = $this->wash_style($value))) {
         $quot = strpos($style, '"') !== false ? "'" : '"';
         $t .= ' style=' . $quot . $style . $quot;
       }
       else if ($key == 'background' || ($key == 'src' && strtolower($node->tagName) == 'img')) { //check tagName anyway
@@ -235,11 +238,12 @@ class washtml
           }
         }
         else if (preg_match('/^data:.+/i', $value)) { // RFC2397
           $t .= ' ' . $key . '="' . htmlspecialchars($value, ENT_QUOTES) . '"';
         }
-      } else
+      }
+      else
         $washed .= ($washed?' ':'') . $key;
     }
     return $t . ($washed && $this->config['show_washed']?' x-washed="'.$washed.'"':'');
   }
 

Vulnerable code:          ($key == 'href' && preg_match('!^([a-z][a-z0-9.+-]+:|//|#).+!i', $value)))
      } else
Fixed code: - Fix XSS issue with href="javascript:" not being removed (#1488613)
         ($key == 'href' && !preg_match('!^javascript!i', $value)
           && preg_match('!^([a-z][a-z0-9.+-]+:|//|#).+!i', $value))
      ) {
      }
      }
      else