Exploiting Drupal Node2Node XSS Vulnerability

24 September 2009

The Drupal Node2Node module was recently flagged by the Drupal security team as insecure and unmaintained (http://drupal.org/node/572852). The module was subsequently unpublished by Drupal, removing it from the main site downloads. This means that the module is no longer supported by Drupal. The Drupal security team announcement did not specify what vulnerabilities were contained within the Node2Node module, but a quick glance at the code and some testing quickly reveals a cross site scripting (XSS) vulnerability in the Node2Node module. To exploit the vulnerability simply follow the proof of concept steps below:

  1. Install Node2Node (it can still be downloaded from http://ftp.drupal.org/files/projects/node2node-6.x-1.2.tar.gz
  2. Enable Node2Node from Administer -> Modules
  3. Create two pieces of content from Create content -> Story
  4. Click Administer -> Site configuration -> Node 2 Node administration
  5. Configure Relationship 1, selecting 'Story' for the Parent and Child.
  6. Enter "<script>alert('xss');</script>" for the 'Name of relationship'
  7. Click 'Save configuration'
  8. Click to the main page and view your first story, click the 'Make target' button
  9. Navigate to your second story and click the 'Edit' link
  10. Observe the JavaScript alerts.

This is just one example but the 'Parent links' and 'Inverse' fields are also subject to XSS vulnerabilities because the module does not sanitize their output when displaying them. This means that a user who could set up node relationships using the Node2Node module could inject XSS into the display pages. XSS is particularly nasty in Drupal because user accounts can easily be hijacked if a logged in Drupal user views pages that render malicious scripts.

The following diff is for a patch to mitigate these vulnerabilities:

--- node2node/node2node.module  2008-11-15 12:13:23.000000000 -0500
+++ node2node_fixed/node2node.module    2009-09-24 14:07:19.780245480 -0400
@@ -456,6 +456,7 @@ function node2node_form_alter(&$form, $f
       $i = 0;
       foreach ($node->parent_nodes as $k=>$pnode) {
+       $pnode = array_map('check_plain', $pnode);
          $form['node2nodeparents']['p_'.$i] = array(
             '#type' => 'hidden',
             '#value' => $i,
@@ -521,6 +522,7 @@ function node2node_form_alter(&$form, $f
       $i = 0;
       foreach ($node->child_nodes as $k=>$cnode) {
+       $cnode = array_map('check_plain', $cnode);
          $form['node2nodechildren']['c_'.$i] = array(
             '#type' => 'hidden',
             '#value' => $i,