Index: includes/form.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/form.inc,v retrieving revision 1.506 diff -u -p -r1.506 form.inc --- includes/form.inc 21 Oct 2010 20:46:58 -0000 1.506 +++ includes/form.inc 27 Oct 2010 05:59:56 -0000 @@ -1145,7 +1145,7 @@ function _form_validate(&$elements, &$fo if (isset($elements['#needs_validation'])) { // Verify that the value is not longer than #maxlength. if (isset($elements['#maxlength']) && drupal_strlen($elements['#value']) > $elements['#maxlength']) { - form_error($elements, $t('!name cannot be longer than %max characters but is currently %length characters long.', array('!name' => empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title'], '%max' => $elements['#maxlength'], '%length' => drupal_strlen($elements['#value'])))); + form_error($elements, $t('!name cannot be longer than %max characters but is currently %length characters long.', array('!name' => empty($elements['#title']) ? check_plain($elements['#parents'][0]) : $elements['#title'], '%max' => $elements['#maxlength'], '%length' => drupal_strlen($elements['#value'])))); } if (isset($elements['#options']) && isset($elements['#value'])) { @@ -1160,7 +1160,7 @@ function _form_validate(&$elements, &$fo foreach ($value as $v) { if (!isset($options[$v])) { form_error($elements, $t('An illegal choice has been detected. Please contact the site administrator.')); - watchdog('form', 'Illegal choice %choice in !name element.', array('%choice' => $v, '!name' => empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title']), WATCHDOG_ERROR); + watchdog('form', 'Illegal choice %choice in !name element.', array('%choice' => $v, '!name' => empty($elements['#title']) ? check_plain($elements['#parents'][0]) : $elements['#title']), WATCHDOG_ERROR); } } } @@ -2775,7 +2775,18 @@ function form_process_radios($element) { $parents_for_id = array_merge($element['#parents'], array($key)); $element[$key] = array( '#type' => 'radio', - '#title' => $choice, + // Code that sets #title from user input must sanitize it to protect + // against XSS. It is possible for #options to be set from unsanitized + // user input, but since this is a generic function, we must use the + // least intrusive filter possible. Modules that use non-admin user + // input for defining radio options should invoke the appropriate + // filter function when setting #options. + '#title' => filter_xss_admin($choice), + // @todo This is the wrong place to call check_plain(), because + // check_plain() is called again when the 'value' attribute is + // output using drupal_attributes(). Evaluate whether this call to + // check_plain() can be safely removed in Drupal 7. Otherwise, + // remove it in Drupal 8. '#return_value' => check_plain($key), '#default_value' => isset($element['#default_value']) ? $element['#default_value'] : NULL, '#attributes' => $element['#attributes'], @@ -2871,7 +2882,13 @@ function form_process_checkboxes($elemen $element[$key] = array( '#type' => 'checkbox', '#processed' => TRUE, - '#title' => $choice, + // Code that sets #title from user input must sanitize it to protect + // against XSS. It is possible for #options to be set from unsanitized + // user input, but since this is a generic function, we must use the + // least intrusive filter possible. Modules that use non-admin user + // input for defining checkbox options should invoke the appropriate + // filter function when setting #options. + '#title' => filter_xss_admin($choice), '#return_value' => $key, '#default_value' => isset($value[$key]) ? $key : NULL, '#attributes' => $element['#attributes'], @@ -3763,6 +3780,12 @@ function theme_form_element_label($varia // If the element is required, a required marker is appended to the label. $required = !empty($element['#required']) ? theme('form_required_marker', array('element' => $element)) : ''; + // @todo In Drupal 8, remove this call to filter_xss_admin(). Code that + // populates an element's #title or #description property from user input is + // responsible for sanitizing it appropriately. We retain this additional + // filtering in Drupal 7 for backwards compatibility only, but other + // functions do not necessarily have this failsafe, so modules must not rely + // on it. $title = filter_xss_admin($element['#title']); $attributes = array();