Index: modules/search/search.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/search/search.module,v
retrieving revision 1.344
diff -u -r1.344 search.module
--- modules/search/search.module	11 Apr 2010 18:54:11 -0000	1.344
+++ modules/search/search.module	13 Apr 2010 16:25:49 -0000
@@ -1023,8 +1023,11 @@
   preg_match_all('/ ("([^"]+)"|(?!OR)([^" ]+))/', ' ' . $keys, $matches);
   $keys = array_merge($matches[2], $matches[3]);
 
-  // Prepare text
+  // Prepare text by stripping HTML tags and decoding HTML entities.
   $text = ' ' . strip_tags(str_replace(array('<', '>'), array(' <', '> '), $text)) . ' ';
+  $text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
+
+  // Slash-escape quotes in the search keyword string.
   array_walk($keys, '_search_excerpt_replace');
   $workkeys = $keys;
 
@@ -1077,7 +1080,8 @@
 
   // If we didn't find anything, return the beginning.
   if (count($ranges) == 0) {
-    return truncate_utf8($text, 256, TRUE, TRUE);
+    return htmlentities(truncate_utf8($text, 256, TRUE, TRUE));
+    
   }
 
   // Sort the text ranges by starting position.
@@ -1108,6 +1112,7 @@
     $out[] = substr($text, $from, $to - $from);
   }
   $text = (isset($newranges[0]) ? '' : '... ') . implode(' ... ', $out) . ' ...';
+  $text = htmlentities($text);
 
   // Highlight keywords. Must be done at once to prevent conflicts ('strong' and '<strong>').
   $text = preg_replace('/' . $boundary . '(' . implode('|', $keys) . ')' . $boundary . '/iu', '<strong>\0</strong>', $text);
@@ -1119,7 +1124,7 @@
  */
 
 /**
- * Helper function for array_walk in search_except.
+ * Helper function for array_walk() in search_excerpt().
  */
 function _search_excerpt_replace(&$text) {
   $text = preg_quote($text, '/');
