Drupal 6/7 Password Policy Module XSS Vulnerability

15 August 2013

Vulnerability Report

Author: Justin C. Klein Keane

Reported: 9 August, 2013

Description of Vulnerability:

Drupal (http://drupal.org) is a robust content management system (CMS) written in PHP and MySQL. The Password Policy module (https://drupal.org/project/password_policy) " provides a way to specify a certain level of password complexity (aka. "password hardening") for user passwords on a system by defining a password policy." The Password Policy module suffers from a persistent (stored) cross site scripting (XSS or arbitrary script injection) vulnerability because it fails to sanitize expiration warning messages before display.

Systems affected:

Password Policy 7.x-1.4 on Drupal 7.22 was tested and shown vulnerable. The Drupal 6 version is also vulnerable.


Attackers can inject arbitrary HTML (including JavaScript) in order to attack site administrators. This could lead to account compromise, which could in turn lead to web server compromise, or expose administrative users to client side malware attacks.

Mitigating factors:

In order to inject arbitrary script malicious attackers must have the access to an account with the 'Administer policies' permission.

Proof of Concept Exploits:

  1. Install and enable the Password Policy module
  2. Navigate to the new policy page at ?q=admin/config/people/password_policy/add
  3. Fill in the "Password Expiration Warning " field with the value "<script>alert('xss');</script>"
  4. Complete the "Name" and "Roles" sections with arbitrary values and click the "Create" button at the bottom of the page.
  5. Click the 'view' link on the policy list page (?q=admin/config/people/password_policy/list) for the new policy
  6. The XSS will manifest on the policy page at ?q=admin/config/people/password_policy/X where X is the policy id


The following patch mitigates this vulnerability:

--- password_policy/password_policy.admin.inc	2013-08-09 11:58:49.237205999 -0400
+++ password_policy/password_policy.admin.inc	2013-08-09 11:59:23.423205888 -0400
@@ -267,7 +267,7 @@ function password_policy_admin_view($pol
     $rows[] = array(t('Expiration'), $policy['expiration']);
   if (!empty($policy['warning'])) {
-    $rows[] = array(t('Warning'), $policy['warning']);
+    $rows[] = array(t('Warning'), check_plain($policy['warning']));
   foreach ($policy['policy'] as $key => $val) {
@@ -391,6 +391,9 @@ function password_policy_admin_form_vali
   if (empty($roles)) {
     form_set_error('roles', t('You must select at least one role for a policy to apply to.'));
+  if (! preg_match("[d, ]", $form_state['values']['warning'])) {
+  	form_set_error('warning', t('Warning must only contain digits or commas'));
+  }

Vendor Response