diff --git a/includes/batch.inc b/includes/batch.inc
index ad56303682484fe9285e3a161f4ff79a00d625b0..2cc41a92211bf5c36e86d0470128241d1eae3e5e 100644
--- a/includes/batch.inc
+++ b/includes/batch.inc
@@ -80,10 +80,10 @@ function _batch_start() {
 function _batch_progress_page_js() {
   $batch = batch_get();
 
-  // The first batch set gets to set the page title
-  // and the initialization and error messages.
+  // The first batch set gets to set the page title and the initialization and
+  // error messages. Only safe strings should be passed in to batch_set().
   $current_set = _batch_current_set();
-  drupal_set_title($current_set['title']);
+  drupal_set_title($current_set['title'], PASS_THROUGH);
   drupal_add_js('misc/progress.js', 'core', 'header', FALSE, FALSE);
 
   $url = url($batch['url'], array('query' => array('id' => $batch['id'])));
@@ -126,7 +126,7 @@ function _batch_progress_page_nojs() {
   $batch =& batch_get();
   $current_set = _batch_current_set();
 
-  drupal_set_title($current_set['title']);
+  drupal_set_title($current_set['title'], PASS_THROUGH);
 
   $new_op = 'do_nojs';
 
diff --git a/includes/form.inc b/includes/form.inc
index 4a0b737ff8a589e261e2fb8a72ee761e897f7d36..037bb9ee6381bb9de8384344ff1462ade75f3194 100644
--- a/includes/form.inc
+++ b/includes/form.inc
@@ -2379,6 +2379,11 @@ function form_clean_id($id = NULL, $flush = FALSE) {
  * batch_process();
  * @endcode
  *
+ * Note - if the batch 'title', 'init_message', 'progress_message',
+ * or 'error_message' could contain any user input, it is the responsibility of
+ * the code calling batch_set() to sanitize them first with a function like
+ * check_plain() or filter_xss().
+ *
  * Sample batch operations:
  * @code
  * // Simple and artificial: load a node of a given type for a given user
diff --git a/includes/path.inc b/includes/path.inc
index 83a7f5b390d8df6273140d1704b3cec71c1f7842..2a7c3eac08080da91356bcc4391364759a860629 100644
--- a/includes/path.inc
+++ b/includes/path.inc
@@ -197,15 +197,20 @@ function drupal_get_title() {
  * @param $title
  *   Optional string value to assign to the page title; or if set to NULL
  *   (default), leaves the current title unchanged.
+ * @param $output
+ *   Optional flag - normally should be left as CHECK_PLAIN. Only set to
+ *   PASS_THROUGH if you have already removed any possibly dangerous code
+ *   from $title using a function like check_plain() or filter_xss(). With this
+ *   flag the string will be passed through unchanged.
  *
  * @return
  *   The updated title of the current page.
  */
-function drupal_set_title($title = NULL) {
+function drupal_set_title($title = NULL, $output = CHECK_PLAIN) {
   static $stored_title;
 
   if (isset($title)) {
-    $stored_title = $title;
+    $stored_title = ($output == PASS_THROUGH) ? $title : check_plain($title);
   }
   return $stored_title;
 }