CVE-2013-0275: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Multiple cross-site scripting (XSS) vulnerabilities in Ganglia Web before 3.5.6 allow remote attackers to inject arbitrary web script or HTML via unspecified vectors.
CWE description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
Published: 2013-03-14T03:12Z
Repository: https://github.com/ganglia/ganglia-web
Language: PHP
Files changed: actions.php, autorotation.php, compare_hosts.php, decompose_graph.php, graph_all_periods.php, header.php, mobile_helper.php, trend_navigation.php, views.php, views_view.php
Commit date: 2013-01-18 15:03:18 -0500
Commit message: Escape special characters. Clean up input

Diff: diff --git a/actions.php b/actions.php
index 461ae1a..2a1a8fc 100644
--- a/actions.php
+++ b/actions.php
@@ -12,17 +12,17 @@ if ( isset($_GET['action']) && $_GET['action'] == "show_views" ) {
 
   <table>
   <?php
   if ( isset($_GET['aggregate']) ) {
   ?>
-     <tr><th>Host regular expression</th><td><?php print join (",", $_GET['hreg']); ?></td></tr>
-     <tr><th>Metric regular expression</th><td><?php print join (",", $_GET['mreg']); ?></td></tr>
+     <tr><th>Host regular expression</th><td><?php print htmlspecialchars( join (",", $_GET['hreg']) ); ?></td></tr>
+     <tr><th>Metric regular expression</th><td><?php print htmlspecialchars( join (",", $_GET['mreg']) ); ?></td></tr>
   <?php
     } else {
   ?>
-     <tr><th>Hostname</th><td><?php print $_GET['host_name']; ?></td></tr>
-     <tr><th>Metric/Report</th><td><?php print $_GET['metric_name']; ?></td></tr>
+     <tr><th>Hostname</th><td><?php print htmlspecialchars($_GET['host_name']); ?></td></tr>
+     <tr><th>Metric/Report</th><td><?php print htmlspecialchars($_GET['metric_name']); ?></td></tr>
   <?php
   }
   ?>
 
   </table>
@@ -33,21 +33,21 @@ if ( isset($_GET['action']) && $_GET['action'] == "show_views" ) {
     // Get all the aggregate form variables and put them in the hidden fields
     if ( isset($_GET['aggregate']) ) {
 	foreach ( $_GET as $key => $value ) {
 	  if ( is_array($value) ) {
 	    foreach ( $value as $index => $value2 ) {
-	      print '<input type="hidden" name="' . $key .'[]" value="' . $value2 . '" />';
+	      print '<input type="hidden" name="' . htmlspecialchars($key) .'[]" value="' . htmlspecialchars($value2) . '" />';
 	    }
 	  } else {
-	    print '<input type="hidden" name="' . $key .'" value="' . $value . '" />';
+	    print '<input type="hidden" name="' . htmlspecialchars($key) .'" value="' . htmlspecialchars($value) . '" />';
 	  }
 	}
     } else {
       // If hostname is not set we assume we are dealing with aggregate graphs
-      print "<input type=\"hidden\" name=\"host_name\" value=\"{$_GET['host_name']}\" />";
+      print "<input type=\"hidden\" name=\"host_name\" value=\"".htmlspecialchars($_GET['host_name'])."\" />";
       $metric_name=$_GET['metric_name'];
-      print "<input type=\"hidden\" name=\"metric_name\" value=\"{$_GET['metric_name']}\" />";
+      print "<input type=\"hidden\" name=\"metric_name\" value=\"".htmlspecialchars($_GET['metric_name'])."\" />";
       print "<input type=\"hidden\" name=\"type\" value=\"{$_GET['type']}\">";
       if (isset($_GET['vl']) && ($_GET['vl'] !== ''))
 	  print "<input type=\"hidden\" name=\"vertical_label\" value=\"" . htmlentities(stripslashes($_GET['vl'])) . "\" />";
       if (isset($_GET['ti']) && ($_GET['ti'] !== ''))
 	  print "<input type=\"hidden\" name=\"title\" value=\"" . htmlentities(stripslashes($_GET['ti'])) . "\" />";
diff --git a/autorotation.php b/autorotation.php
index 267435e..974af1e 100644
--- a/autorotation.php
+++ b/autorotation.php
@@ -125,11 +125,11 @@ if ( ! isset($_REQUEST['view_name']) ) {
       <img src="<?php echo $gangliapath . "&r=week&z=${small_size}&" . $view_elements[$id]['graph_args']; ?>">
       <img src="<?php echo $gangliapath . "&r=month&z=${small_size}&" . $view_elements[$id]['graph_args']; ?>">
     <div style="margin-top: 10px; font-size: 48px; text-align: center;"><?php echo date(DATE_RFC850); ?></div>
     <p>
     <center><form>
-    <input type="hidden" name="view_name" value="<?php print $_GET['view_name'] ?>">
+    <input type="hidden" name="view_name" value="<?php print htmlspecialchars($_GET['view_name']) ?>">
     <input type="hidden" name="id" value="<?php print $nextid ?>">
     Rotate graphs every <select onChange="form.submit();" name="timeout">
     <?php
       for ( $i = 10 ; $i <= 90 ; $i += 5 ) {
 	if ( $timeout == $i )
diff --git a/compare_hosts.php b/compare_hosts.php
index a979a21..d8637cd 100644
--- a/compare_hosts.php
+++ b/compare_hosts.php
@@ -54,16 +54,16 @@ foreach ( $host_metrics as $name => $value )
 
 
 $hreg = "";
 if (array_key_exists('hreg', $_GET)) {
   foreach ( $_GET['hreg'] as $index => $arg ) {
-    $hreg .= "&hreg[]=" . $arg;
+    $hreg .= "&hreg[]=" . rawurlencode($arg);
   }
 }
 
 if ( isset($_GET['hreg']) ) {
-  $data->assign("hreg_arg", $_GET['hreg'][0]);
+  $data->assign("hreg_arg", htmlspecialchars($_GET['hreg'][0]) );
 } else {
   $data->assign("hreg_arg", "");
 }
 
 $size = isset($clustergraphsize) ? $clustergraphsize : 'default';
diff --git a/decompose_graph.php b/decompose_graph.php
index 60b7e21..da16515 100644
--- a/decompose_graph.php
+++ b/decompose_graph.php
@@ -21,14 +21,14 @@ if ( !isset($_GET['hreg']) or !isset($_GET['mreg']) ) {
 $graph_type = "line";
 $line_width = "2";
 $graph_config = build_aggregate_graph_config ($graph_type, $line_width, $_GET['hreg'], $_GET['mreg']);
 
 foreach ( $_GET['hreg'] as $index => $arg ) {
-  print "<input type=hidden name=hreg[] value='" . $arg . "'>";
+  print "<input type=hidden name=hreg[] value='" . htmlspecialchars($arg) . "'>";
 }
 foreach ( $_GET['mreg'] as $index => $arg ) {
-  print "<input type=hidden name=mreg[] value='" . $arg . "'>";
+  print "<input type=hidden name=mreg[] value='" . htmlspecialchars($arg) . "'>";
 }
 
 $size = isset($clustergraphsize) ? $clustergraphsize : 'default';
 $size = $size == 'medium' ? 'default' : $size; //set to 'default' to preserve old behavior
 
diff --git a/graph_all_periods.php b/graph_all_periods.php
index 5622850..bbbc84d 100644
--- a/graph_all_periods.php
+++ b/graph_all_periods.php
@@ -51,16 +51,16 @@ include_once "./global.php";
 // get arguments are an array rebuild them. For example with hreg (host regex)
 $ignore_keys_list = array("r", "z", "st", "cs", "ce", "hc");
 
 foreach ($_GET as $key => $value) {
   if ( ! in_array($key, $ignore_keys_list) && ! is_array($value))
-    $query_string_array[] = "$key=" . urlencode($value);
+    $query_string_array[] = rawurlencode($key) . "=" . urlencode($value);
 
   // $_GET argument is an array. Rebuild it to pass it on
   if ( is_array($value) ) {
     foreach ( $value as $index => $value2 )
-      $query_string_array[] = $key . "[]=" . urlencode($value2);
+      $query_string_array[] = rawurlencode($key) . "[]=" . urlencode($value2);
 
   }
 }
 
 // If we are in the mobile mode set the proper graph sizes
@@ -75,24 +75,24 @@ if ( isset($_GET['mobile'])) {
 // Join all the query_string arguments
 $query_string = "&amp;" . join("&amp;", $query_string_array);
 
 // Descriptive host/aggregate graph
 if (isset($_GET['h']) && ($_GET['h'] != ''))
-  $description = $_GET['h'];
+  $description = htmlspecialchars($_GET['h']);
 else if (isset($_GET['c']) && ($_GET['c'] != ''))
-  $description = $_GET['c'];
+  $description = htmlspecialchars($_GET['c']);
 else if (is_array($_GET['hreg']))
-  $description = join(",", $_GET['hreg']);
+  $description = htmlspecialchars( join(",", $_GET['hreg']) );
 else
   $description = "Unknown";
 
 if (isset($_GET['g'])) 
-  $metric_description = $_GET['g'];
+  $metric_description = htmlspecialchars($_GET['g']);
 else if ( isset($_GET['m'] ))
-  $metric_description = $_GET['m'];
+  $metric_description = htmlspecialchars($_GET['m']);
 else if (is_array($_GET['mreg']) )
-  $metric_description = join(",", $_GET['mreg']);
+  $metric_description = htmlspecialchars( join(",", $_GET['mreg']) );
 else
   $metric_description = "Unknown";
 
 # Determine if it's aggregate graph
 if ( preg_match("/aggregate=1/", $query_string) )
@@ -150,11 +150,11 @@ if ( ! isset($_REQUEST['mobile']) ) {
 if ( isset($_REQUEST['mobile'])) {
 ?>
     <div data-role="page" class="ganglia-mobile" id="view-home">
     <div data-role="header">
       <a href="#" class="ui-btn-left" data-icon="arrow-l" onclick="history.back(); return false">Back</a>
-      <h3><?php if (isset($_GET['g'])) echo $_GET['g']; else echo $_GET['m']; ?></h3>
+      <h3><?php if (isset($_GET['g'])) echo htmlspecialchars($_GET['g']); else echo htmlspecialchars($_GET['m']); ?></h3>
       <a href="#mobile-home">Home</a>
     </div>
     <div data-role="content">
 <?php
 }
diff --git a/header.php b/header.php
index b3789e3..d0a30c2 100755
--- a/header.php
+++ b/header.php
@@ -527,11 +527,11 @@ if($conf['auth_system'] == 'enabled') {
 
 
 if ( $conf['overlay_events'] == true )
   $data->assign('overlay_events', true);
 
-$data->assign('selected_tab', $user['selected_tab']);
+$data->assign('selected_tab', htmlspecialchars($user['selected_tab']) );
 $data->assign('view_name', $user['viewname']);
 
 $additional_buttons = "";
 if ($context == 'views' || $context == 'decompose_graph' || $context == 'host') {
   $additional_buttons = '<input title="Hide/Show Events" type="checkbox" id="show_all_events" onclick="showAllEvents(this.checked)"/><label for="show_all_events">Hide/Show Events</label>';
diff --git a/mobile_helper.php b/mobile_helper.php
index 1e8765d..2a0e51d 100644
--- a/mobile_helper.php
+++ b/mobile_helper.php
@@ -12,11 +12,11 @@ include_once "./get_ganglia.php";
 if ( isset($_GET['view_name'])) {
 ?>  
   <div data-role="page" class="ganglia-mobile" id="view-home">
     <div data-role="header">
       <a href="#" class="ui-btn-left" data-icon="arrow-l" onclick="history.back(); return false">Back</a>
-      <h1>View <?php print $_GET['view_name']; ?></h1>
+      <h1>View <?php print htmlspecialchars($_GET['view_name']); ?></h1>
       <a href="#mobile-home">Home</a>
       <div data-role="navbar">
 	<ul>
   <?php
 
@@ -37,11 +37,11 @@ if ( isset($_GET['view_name'])) {
      $url=rawurlencode($v);
      if ($v == $range) {
       $checked = "class=\"ui-btn-active\"";
       $range_menu .= "<li><a $checked href='#' onclick='return false;'>$v</a></li>";
     } else {
-      $range_menu .= "<li><a href='mobile_helper.php?view_name=" . $_GET['view_name'] . "&r=" . $v . "&cs=&ce='>$v</a></li>";
+      $range_menu .= "<li><a href='mobile_helper.php?view_name=" . rawurlencode($_GET['view_name']) . "&r=" . $v . "&cs=&ce='>$v</a></li>";
     }
 
   }
     print $range_menu;
   ?>
@@ -59,13 +59,13 @@ if ( isset($_GET['view_name'])) {
   
       $view_elements = get_view_graph_elements($view);
 
       $range_args = "";
       if ( isset($_GET['r']) && $_GET['r'] != "" ) 
-	    $range_args .= "&r=" . $_GET['r'];
+	    $range_args .= "&r=" . rawurlencode($_GET['r']);
       if ( isset($_GET['cs']) && isset($_GET['ce']) ) 
-	    $range_args .= "&cs=" . $_GET['cs'] . "&ce=" . $_GET['ce'];
+	    $range_args .= "&cs=" . rawurlencode($_GET['cs']) . "&ce=" . rawurlencode($_GET['ce']);
 
       if ( count($view_elements) != 0 ) {
 	foreach ( $view_elements as $id => $element ) {
 	  print "
 	  <A HREF=\"./graph_all_periods.php?mobile=1&" . $element['graph_args'] ."&z=mobile\">
@@ -91,11 +91,11 @@ if ( isset($_GET['show_cluster_metrics'])) {
   $clustername = $_GET['c'];
 ?>  
   <div data-role="page" class="ganglia-mobile" id="viewhost-<?php print $hostname; ?>">
     <div data-role="header" data-position="fixed">
       <a href="#" class="ui-btn-left" data-icon="arrow-l" onclick="history.back(); return false">Back</a>
-      <h3>Cluster <?php print $clustername; ?></h3>
+      <h3>Cluster <?php print htmlspecialchars($clustername); ?></h3>
       <a href="#mobile-home">Home</a>
         <div data-role="navbar">
 	<ul>
   <?php
 	// Header bar support up to 5 items. 5+ items will be shown in multiple
@@ -112,22 +112,22 @@ if ( isset($_GET['show_cluster_metrics'])) {
 	   $url=rawurlencode($v);
 	   if ($v == $range) {
 	     $checked = "class=\"ui-btn-active\"";
       	     $range_menu .= "<li><a $checked href='#'>$v</a></li>";
 	  } else {
-      	     $range_menu .= "<li><a href='mobile_helper.php?show_cluster_metrics=1&c=" . $clustername . "&r=" . $v . "&cs=&ce='>$v</a></li>";
+      	     $range_menu .= "<li><a href='mobile_helper.php?show_cluster_metrics=1&c=" . rawurlencode($clustername) . "&r=" . $v . "&cs=&ce='>$v</a></li>";
 	  }
 	}
 	  print $range_menu;
     ?>
 	</ul>
       </div><!-- /navbar -->
     </div><!-- /header -->
   
     <div data-role="content">
 <?php
-    $graph_args = "c=$clustername&r=$range";
+    $graph_args = "c=".rawurlencode($clustername)."&r=".rawurlencode($range);
     
     ///////////////////////////////////////////////////////////////////////////
     // Let's find out what optional reports are included
     // First we find out what the default (site-wide) reports are then look
     // for host specific included or excluded reports
@@ -135,11 +135,14 @@ if ( isset($_GET['show_cluster_metrics'])) {
     $default_reports = array("included_reports" => array(), "excluded_reports" => array());
     if ( is_file($conf['conf_dir'] . "/default.json") ) {
       $default_reports = array_merge($default_reports,json_decode(file_get_contents($conf['conf_dir'] . "/default.json"), TRUE));
     }
     
-    $cluster_file = $conf['conf_dir'] . "/cluster_" . $clustername . ".json";
+    $cluster_file = $conf['conf_dir'] . "/cluster_" . preg_replace('/[^a-zA-Z0-9_-]/', '', $clustername) . ".json";
+    if ( pathinfo( $cluster_file, PATHINFO_DIRNAME ) != $conf['conf_dir'] ) {
+      die('Invalid path detected');
+    }
     $override_reports = array("included_reports" => array(), "excluded_reports" => array());
     if ( is_file($cluster_file) ) {
       $override_reports = array_merge($override_reports, json_decode(file_get_contents($cluster_file), TRUE));
     }
     
@@ -152,12 +155,12 @@ if ( isset($_GET['show_cluster_metrics'])) {
     $reports["excluded_reports"] = array_unique($reports["excluded_reports"]);
     
     foreach ( $reports["included_reports"] as $index => $report_name ) {
       if ( ! in_array( $report_name, $reports["excluded_reports"] ) ) {
 	print "<a name=metric_" . $report_name . ">
-	<A HREF=\"./graph_all_periods.php?mobile=1&$graph_args&amp;g=" . $report_name . "&amp;z=mobile&amp;c=$clustername\">
-	<IMG BORDER=0 ALT=\"$clustername\" SRC=\"./graph.php?$graph_args&amp;g=" . $report_name ."&amp;z=mobile&amp;c=$clustername\"></A>
+	<A HREF=\"./graph_all_periods.php?mobile=1&$graph_args&amp;g=" . $report_name . "&amp;z=mobile&amp;c=".rawurlencode($clustername)."\">
+	<IMG BORDER=0 ALT=\"".rawurlencode($clustername)."\" SRC=\"./graph.php?$graph_args&amp;g=" . $report_name ."&amp;z=mobile&amp;c=".rawurlencode($clustername)."\"></A>
 	";
       }
 
     }
 
@@ -171,14 +174,14 @@ if ( isset($_GET['show_cluster_metrics'])) {
 ///////////////////////////////////////////////////////////////////////////////
 if ( isset($_GET['show_host_metrics'])) {
   $hostname = $_GET['h'];
   $clustername = $_GET['c'];
 ?>
-  <div data-role="page" class="ganglia-mobile" id="viewhost-<?php print $hostname; ?>">
+  <div data-role="page" class="ganglia-mobile" id="viewhost-<?php print htmlspecialchars($hostname); ?>">
     <div data-role="header" data-position="fixed">
       <a href="#" class="ui-btn-left" data-icon="arrow-l" onclick="history.back(); return false">Back</a>
-      <h3>Host <?php print $hostname; ?></h3>
+      <h3>Host <?php print htmlspecialchars($hostname); ?></h3>
       <a href="#mobile-home">Home</a>
         <div data-role="navbar">
 	<ul>
   <?php
 	// Header bar support up to 5 items. 5+ items will be shown in multiple
@@ -195,22 +198,22 @@ if ( isset($_GET['show_host_metrics'])) {
 	   $url=rawurlencode($v);
 	   if ($v == $range) {
 	     $checked = "class=\"ui-btn-active\"";
       	     $range_menu .= "<li><a $checked href='#'>$v</a></li>";
 	  } else {
-      	     $range_menu .= "<li><a href='mobile_helper.php?show_host_metrics=1&h=" . $hostname . "&c=" . $clustername . "&r=" . $v . "&cs=&ce='>$v</a></li>";
+      	     $range_menu .= "<li><a href='mobile_helper.php?show_host_metrics=1&h=" . rawurlencode($hostname) . "&c=" . rawurlencode($clustername) . "&r=" . $v . "&cs=&ce='>$v</a></li>";
 	  }
 	}
 	  print $range_menu;
     ?>
 	</ul>
       </div><!-- /navbar -->
     </div><!-- /header -->
   
     <div data-role="content">
 <?php
-    $graph_args = "h=$hostname&c=$clustername&r=$range";
+    $graph_args = "h=".rawurlencode($hostname)."&c=".rawurlencode($clustername)."&r=".rawurlencode($range);
     
     ///////////////////////////////////////////////////////////////////////////
     // Let's find out what optional reports are included
     // First we find out what the default (site-wide) reports are then look
     // for host specific included or excluded reports
@@ -218,11 +221,14 @@ if ( isset($_GET['show_host_metrics'])) {
     $default_reports = array("included_reports" => array(), "excluded_reports" => array());
     if ( is_file($conf['conf_dir'] . "/default.json") ) {
       $default_reports = array_merge($default_reports,json_decode(file_get_contents($conf['conf_dir'] . "/default.json"), TRUE));
     }
     
-    $host_file = $conf['conf_dir'] . "/host_" . $hostname . ".json";
+    $host_file = $conf['conf_dir'] . "/host_" . preg_replace('/[^a-zA-Z0-9_-]/', '', $hostname) . ".json";
+    if ( pathinfo( $host_file, PATHINFO_DIRNAME ) != $conf['conf_dir'] ) {
+      die('Invalid path detected');
+    }
     $override_reports = array("included_reports" => array(), "excluded_reports" => array());
     if ( is_file($host_file) ) {
       $override_reports = array_merge($override_reports, json_decode(file_get_contents($host_file), TRUE));
     }
     
@@ -237,11 +243,11 @@ if ( isset($_GET['show_host_metrics'])) {
     foreach ( $reports["included_reports"] as $index => $report_name ) {
     
       if ( ! in_array( $report_name, $reports["excluded_reports"] ) ) {
 	print "
 	<A HREF=\"./graph_all_periods.php?mobile=1&$graph_args&amp;g=" . $report_name . "&amp;z=large\">
-	<IMG BORDER=0 ALT=\"$clustername\" SRC=\"./graph.php?$graph_args&amp;g=" . $report_name ."&amp;z=mobile\"></A>";
+	<IMG BORDER=0 ALT=\"".rawurlencode($clustername)."\" SRC=\"./graph.php?$graph_args&amp;g=" . $report_name ."&amp;z=mobile\"></A>";
       }
     }
     ?>  
 <?php
 
@@ -258,12 +264,12 @@ foreach ($metrics as $metric_name => $metric_attributes) {
   } elseif ($metric_attributes['SLOPE'] == "zero" or (isset($always_constant[$metric_name]) and $always_constant[$metric_name])) {
 	$c_metrics[$metric_name] = $v;
   } else if (isset($reports[$metric_name]) and $reports[$metric])
     continue;
   else {
-    $metric_graphargs = "c=$clustername&amp;h=$hostname&amp;v=$metric_attributes[VAL]"
-      ."&amp;m=$metric_name&amp;r=$range&amp;z=$size&amp;jr=$jobrange"
+    $metric_graphargs = "c=".rawurlencode($clustername)."&amp;h=".rawurlencode($hostname)."&amp;v=".rawurlencode($metric_attributes[VAL])
+      ."&amp;m=$metric_name&amp;r=".rawurlencode($range)."&amp;z=$size&amp;jr=$jobrange"
       ."&amp;js=$jobstart&amp;st=$cluster[LOCALTIME]";
     if ($cs)
        $metric_graphargs .= "&amp;cs=" . rawurlencode($cs);
     if ($ce)
        $metric_graphargs .= "&amp;ce=" . rawurlencode($ce);
@@ -300,11 +306,11 @@ foreach ( $g_metrics_group as $metric_group_name => $metric_group_members ) {
 	<h3><?php print $metric_group_name . " (" . sizeof($metric_group_members) . ")"; ?></h3>
 <?php
       foreach ( $metric_group_members as $index => $metric_name ) {
 	print "
 	<A HREF=\"./graph_all_periods.php?mobile=1&" . $g_metrics[$metric_name]['graph'] .  "\">
-	<IMG BORDER=0 ALT=\"$clustername\" SRC=\"./graph.php?" . $g_metrics[$metric_name]['graph'] . "\"></A>";
+	<IMG BORDER=0 ALT=\"".htmlspecialchars($clustername)."\" SRC=\"./graph.php?" . $g_metrics[$metric_name]['graph'] . "\"></A>";
       }
 ?>
       </div> <!-- /collapsible -->
 <?php
 } // end of foreach ( $g_metrics_group
diff --git a/trend_navigation.php b/trend_navigation.php
index e71070b..2d5f8a1 100644
--- a/trend_navigation.php
+++ b/trend_navigation.php
@@ -8,15 +8,15 @@ if ( !isset($_REQUEST['trendhistory']) )
 
 $drop_args = array("trendrange", "trendhistory");
 
 foreach ( $_REQUEST as $key => $value ) {
   if ( ! in_array($key, $drop_args) )
-    $graph_args[] = $key . "=" . str_replace("_/graph_php?", "", $value);
+    $graph_args[] = rawurlencode($key) . "=" . rawurlencode( str_replace("_/graph_php?", "", $value) );
 }
 
 $query_string = preg_replace("/(&trendrange=)(\d+)/", "", $_SERVER['QUERY_STRING'] );
-$query_string = preg_replace("/(&trendhistory=)(\d+)/", "", $query_string);
+$query_string = preg_replace("/(&trendhistory=)(\d+)/", "", htmlspecialchars($query_string, ENT_QUOTES) );
 
 
 ?>
 <center>
 <div id="trend_range_menu">
@@ -57,6 +57,6 @@ foreach ( $months_ahead as $index => $month ) {
 </center>
 <script type="text/javascript">
   $(function () {
     $("#trend_range_menu").buttonset();
   });
-</script>
\ No newline at end of file
+</script>
diff --git a/views.php b/views.php
index 76391dc..baa422b 100644
--- a/views.php
+++ b/views.php
@@ -8,11 +8,11 @@ if( ! checkAccess(GangliaAcl::ALL_VIEWS, GangliaAcl::VIEW, $conf) ) {
 }
 
 // Load the metric caching code we use if we need to display graphs
 retrieve_metrics_cache();
 
-$base = isset($_GET['base']) ? $_GET['base'] . "/" : "";
+$base = isset($_GET['base']) ? rawurlencode($_GET['base']) . "/" : "";
 ?>
 
 <html>
 <head>
 <script type="text/javascript" src="<?php print $base; ?>js/jquery-1.8.2.min.js"></script>
@@ -31,18 +31,18 @@ $base = isset($_GET['base']) ? $_GET['base'] . "/" : "";
   foreach ($available_views as $view_id => $view) {
     if ($view['view_name'] == $view_name) {
       $view_elements = get_view_graph_elements($view);
       $range_args = "";
       if (isset($_GET['r']) && $_GET['r'] != "") 
-	$range_args .= "&amp;r=" . $_GET['r'];
+	$range_args .= "&amp;r=" . rawurlencode($_GET['r']);
       if (isset($_GET['cs']) && isset($_GET['ce'])) 
-	$range_args .= "&amp;cs=" . $_GET['cs'] . "&amp;ce=" . $_GET['ce'];
+	$range_args .= "&amp;cs=" . rawurlencode($_GET['cs']) . "&amp;ce=" . rawurlencode($_GET['ce']);
 
       if (count($view_elements) != 0) {
 	foreach ($view_elements as $id => $element) {
 	  $legend = isset($element['hostname']) ? $element['hostname'] : "Aggregate graph";
-          $base = isset($_GET['base']) ? $_GET['base'] : '.';
+          $base = isset($_GET['base']) ? rawurlencode($_GET['base']) : '.';
 	  print "<a href=\"" . $base . "/graph_all_periods.php?" . htmlentities($element['graph_args']) ."&amp;z=large\"><img title=\"" . $legend . " - " . $element['name'] . "\" border=0 src=\"" . $base . "/graph.php?" . htmlentities($element['graph_args']) . "&amp;z=small" . $range_args .  "\" style=\"padding:2px;\"></a>";
 	}
       } else {
 	print "No graphs defined for this view. Please add some";
       }
diff --git a/views_view.php b/views_view.php
index 53c6165..3ec6f5a 100644
--- a/views_view.php
+++ b/views_view.php
@@ -30,16 +30,19 @@ if (isset($_GET['create_view'])) {
                 " already exists.";
     } else {
       $empty_view = array ("view_name" => $_GET['view_name'],
                            "items" => array());
       $view_suffix = str_replace(" ", "_", $_GET['view_name']);
-      $view_filename = $conf['views_dir'] . "/view_" . $view_suffix . ".json";
+      $view_filename = $conf['views_dir'] . "/view_" . preg_replace('/[^a-zA-Z0-9_-]/', '', $view_suffix) . ".json";
+      if ( pathinfo( $view_filename, PATHINFO_DIRNAME ) != $conf['views_dir'] ) {
+        die('Invalid path detected');
+      }
       $json = json_encode($empty_view);
       if (file_put_contents($view_filename, 
                             json_prettyprint($json)) === FALSE) {
         $output = "<strong>Alert:</strong>" .
-                  " Can't write to file $view_filename." .
+                  " Can't write to file " . htmlspecialchars($view_filename) .
                   " Perhaps permissions are wrong.";
       } else {
         $output = "View has been created successfully.";
       }
     }
@@ -77,11 +80,14 @@ if (isset($_GET['delete_view'])) {
       $output = "<strong>Alert:</strong> View with the name " .
       $_GET['view_name'] . 
       " does not exist.";
     } else {
       $view_suffix = str_replace(" ", "_", $_GET['view_name']);
-      $view_filename = $conf['views_dir'] . "/view_" . $view_suffix . ".json";
+      $view_filename = $conf['views_dir'] . "/view_" . preg_replace('/[^a-zA-Z0-9_-]/', '', $view_suffix) . ".json";
+      if ( pathinfo( $view_filename, PATHINFO_DIRNAME ) != $conf['views_dir'] ) {
+        die('Invalid path detected');
+      }
       if (unlink($view_filename) === FALSE) {
         $output = "<strong>Alert:</strong>" .
                   " Can't remove file $view_filename." .
                   " Perhaps permissions are wrong.";
       } else {

Vulnerable code:      <tr><th>Host regular expression</th><td><?php print join (",", $_GET['hreg']); ?></td></tr>
     <tr><th>Metric regular expression</th><td><?php print join (",", $_GET['mreg']); ?></td></tr>
     <tr><th>Hostname</th><td><?php print $_GET['host_name']; ?></td></tr>
     <tr><th>Metric/Report</th><td><?php print $_GET['metric_name']; ?></td></tr>
	      print '<input type="hidden" name="' . $key .'[]" value="' . $value2 . '" />';
	    print '<input type="hidden" name="' . $key .'" value="' . $value . '" />';
      print "<input type=\"hidden\" name=\"host_name\" value=\"{$_GET['host_name']}\" />";
      print "<input type=\"hidden\" name=\"metric_name\" value=\"{$_GET['metric_name']}\" />";
    <input type="hidden" name="view_name" value="<?php print $_GET['view_name'] ?>">
    $hreg .= "&hreg[]=" . $arg;
  $data->assign("hreg_arg", $_GET['hreg'][0]);
  print "<input type=hidden name=hreg[] value='" . $arg . "'>";
  print "<input type=hidden name=mreg[] value='" . $arg . "'>";
    $query_string_array[] = "$key=" . urlencode($value);
      $query_string_array[] = $key . "[]=" . urlencode($value2);
  $description = $_GET['h'];
  $description = $_GET['c'];
  $description = join(",", $_GET['hreg']);
  $metric_description = $_GET['g'];
  $metric_description = $_GET['m'];
  $metric_description = join(",", $_GET['mreg']);
      <h3><?php if (isset($_GET['g'])) echo $_GET['g']; else echo $_GET['m']; ?></h3>
$data->assign('selected_tab', $user['selected_tab']);
      <h1>View <?php print $_GET['view_name']; ?></h1>
      $range_menu .= "<li><a href='mobile_helper.php?view_name=" . $_GET['view_name'] . "&r=" . $v . "&cs=&ce='>$v</a></li>";
	    $range_args .= "&r=" . $_GET['r'];
	    $range_args .= "&cs=" . $_GET['cs'] . "&ce=" . $_GET['ce'];
      <h3>Cluster <?php print $clustername; ?></h3>
      	     $range_menu .= "<li><a href='mobile_helper.php?show_cluster_metrics=1&c=" . $clustername . "&r=" . $v . "&cs=&ce='>$v</a></li>";
    $graph_args = "c=$clustername&r=$range";
    $cluster_file = $conf['conf_dir'] . "/cluster_" . $clustername . ".json";
	<A HREF=\"./graph_all_periods.php?mobile=1&$graph_args&amp;g=" . $report_name . "&amp;z=mobile&amp;c=$clustername\">
	<IMG BORDER=0 ALT=\"$clustername\" SRC=\"./graph.php?$graph_args&amp;g=" . $report_name ."&amp;z=mobile&amp;c=$clustername\"></A>
  <div data-role="page" class="ganglia-mobile" id="viewhost-<?php print $hostname; ?>">
      <h3>Host <?php print $hostname; ?></h3>
      	     $range_menu .= "<li><a href='mobile_helper.php?show_host_metrics=1&h=" . $hostname . "&c=" . $clustername . "&r=" . $v . "&cs=&ce='>$v</a></li>";
    $graph_args = "h=$hostname&c=$clustername&r=$range";
    $host_file = $conf['conf_dir'] . "/host_" . $hostname . ".json";
	<IMG BORDER=0 ALT=\"$clustername\" SRC=\"./graph.php?$graph_args&amp;g=" . $report_name ."&amp;z=mobile\"></A>";
    $metric_graphargs = "c=$clustername&amp;h=$hostname&amp;v=$metric_attributes[VAL]"
      ."&amp;m=$metric_name&amp;r=$range&amp;z=$size&amp;jr=$jobrange"
	<IMG BORDER=0 ALT=\"$clustername\" SRC=\"./graph.php?" . $g_metrics[$metric_name]['graph'] . "\"></A>";
    $graph_args[] = $key . "=" . str_replace("_/graph_php?", "", $value);
$query_string = preg_replace("/(&trendhistory=)(\d+)/", "", $query_string);
</script>
$base = isset($_GET['base']) ? $_GET['base'] . "/" : "";
	$range_args .= "&amp;r=" . $_GET['r'];
	$range_args .= "&amp;cs=" . $_GET['cs'] . "&amp;ce=" . $_GET['ce'];
          $base = isset($_GET['base']) ? $_GET['base'] : '.';
      $view_filename = $conf['views_dir'] . "/view_" . $view_suffix . ".json";
                  " Can't write to file $view_filename." .
      $view_filename = $conf['views_dir'] . "/view_" . $view_suffix . ".json";
Fixed code:      <tr><th>Host regular expression</th><td><?php print htmlspecialchars( join (",", $_GET['hreg']) ); ?></td></tr>
     <tr><th>Metric regular expression</th><td><?php print htmlspecialchars( join (",", $_GET['mreg']) ); ?></td></tr>
     <tr><th>Hostname</th><td><?php print htmlspecialchars($_GET['host_name']); ?></td></tr>
     <tr><th>Metric/Report</th><td><?php print htmlspecialchars($_GET['metric_name']); ?></td></tr>
	      print '<input type="hidden" name="' . htmlspecialchars($key) .'[]" value="' . htmlspecialchars($value2) . '" />';
	    print '<input type="hidden" name="' . htmlspecialchars($key) .'" value="' . htmlspecialchars($value) . '" />';
      print "<input type=\"hidden\" name=\"host_name\" value=\"".htmlspecialchars($_GET['host_name'])."\" />";
      print "<input type=\"hidden\" name=\"metric_name\" value=\"".htmlspecialchars($_GET['metric_name'])."\" />";
    <input type="hidden" name="view_name" value="<?php print htmlspecialchars($_GET['view_name']) ?>">
    $hreg .= "&hreg[]=" . rawurlencode($arg);
  $data->assign("hreg_arg", htmlspecialchars($_GET['hreg'][0]) );
  print "<input type=hidden name=hreg[] value='" . htmlspecialchars($arg) . "'>";
  print "<input type=hidden name=mreg[] value='" . htmlspecialchars($arg) . "'>";
    $query_string_array[] = rawurlencode($key) . "=" . urlencode($value);
      $query_string_array[] = rawurlencode($key) . "[]=" . urlencode($value2);
  $description = htmlspecialchars($_GET['h']);
  $description = htmlspecialchars($_GET['c']);
  $description = htmlspecialchars( join(",", $_GET['hreg']) );
  $metric_description = htmlspecialchars($_GET['g']);
  $metric_description = htmlspecialchars($_GET['m']);
  $metric_description = htmlspecialchars( join(",", $_GET['mreg']) );
      <h3><?php if (isset($_GET['g'])) echo htmlspecialchars($_GET['g']); else echo htmlspecialchars($_GET['m']); ?></h3>
$data->assign('selected_tab', htmlspecialchars($user['selected_tab']) );
      <h1>View <?php print htmlspecialchars($_GET['view_name']); ?></h1>
      $range_menu .= "<li><a href='mobile_helper.php?view_name=" . rawurlencode($_GET['view_name']) . "&r=" . $v . "&cs=&ce='>$v</a></li>";
	    $range_args .= "&r=" . rawurlencode($_GET['r']);
	    $range_args .= "&cs=" . rawurlencode($_GET['cs']) . "&ce=" . rawurlencode($_GET['ce']);
      <h3>Cluster <?php print htmlspecialchars($clustername); ?></h3>
      	     $range_menu .= "<li><a href='mobile_helper.php?show_cluster_metrics=1&c=" . rawurlencode($clustername) . "&r=" . $v . "&cs=&ce='>$v</a></li>";
    $graph_args = "c=".rawurlencode($clustername)."&r=".rawurlencode($range);
    $cluster_file = $conf['conf_dir'] . "/cluster_" . preg_replace('/[^a-zA-Z0-9_-]/', '', $clustername) . ".json";
    if ( pathinfo( $cluster_file, PATHINFO_DIRNAME ) != $conf['conf_dir'] ) {
      die('Invalid path detected');
    }
	<A HREF=\"./graph_all_periods.php?mobile=1&$graph_args&amp;g=" . $report_name . "&amp;z=mobile&amp;c=".rawurlencode($clustername)."\">
	<IMG BORDER=0 ALT=\"".rawurlencode($clustername)."\" SRC=\"./graph.php?$graph_args&amp;g=" . $report_name ."&amp;z=mobile&amp;c=".rawurlencode($clustername)."\"></A>
  <div data-role="page" class="ganglia-mobile" id="viewhost-<?php print htmlspecialchars($hostname); ?>">
      <h3>Host <?php print htmlspecialchars($hostname); ?></h3>
      	     $range_menu .= "<li><a href='mobile_helper.php?show_host_metrics=1&h=" . rawurlencode($hostname) . "&c=" . rawurlencode($clustername) . "&r=" . $v . "&cs=&ce='>$v</a></li>";
    $graph_args = "h=".rawurlencode($hostname)."&c=".rawurlencode($clustername)."&r=".rawurlencode($range);
    $host_file = $conf['conf_dir'] . "/host_" . preg_replace('/[^a-zA-Z0-9_-]/', '', $hostname) . ".json";
    if ( pathinfo( $host_file, PATHINFO_DIRNAME ) != $conf['conf_dir'] ) {
      die('Invalid path detected');
    }
	<IMG BORDER=0 ALT=\"".rawurlencode($clustername)."\" SRC=\"./graph.php?$graph_args&amp;g=" . $report_name ."&amp;z=mobile\"></A>";
    $metric_graphargs = "c=".rawurlencode($clustername)."&amp;h=".rawurlencode($hostname)."&amp;v=".rawurlencode($metric_attributes[VAL])
      ."&amp;m=$metric_name&amp;r=".rawurlencode($range)."&amp;z=$size&amp;jr=$jobrange"
	<IMG BORDER=0 ALT=\"".htmlspecialchars($clustername)."\" SRC=\"./graph.php?" . $g_metrics[$metric_name]['graph'] . "\"></A>";
    $graph_args[] = rawurlencode($key) . "=" . rawurlencode( str_replace("_/graph_php?", "", $value) );
$query_string = preg_replace("/(&trendhistory=)(\d+)/", "", htmlspecialchars($query_string, ENT_QUOTES) );
</script>
$base = isset($_GET['base']) ? rawurlencode($_GET['base']) . "/" : "";
	$range_args .= "&amp;r=" . rawurlencode($_GET['r']);
	$range_args .= "&amp;cs=" . rawurlencode($_GET['cs']) . "&amp;ce=" . rawurlencode($_GET['ce']);
          $base = isset($_GET['base']) ? rawurlencode($_GET['base']) : '.';
      $view_filename = $conf['views_dir'] . "/view_" . preg_replace('/[^a-zA-Z0-9_-]/', '', $view_suffix) . ".json";
      if ( pathinfo( $view_filename, PATHINFO_DIRNAME ) != $conf['views_dir'] ) {
        die('Invalid path detected');
      }
                  " Can't write to file " . htmlspecialchars($view_filename) .
      $view_filename = $conf['views_dir'] . "/view_" . preg_replace('/[^a-zA-Z0-9_-]/', '', $view_suffix) . ".json";
      if ( pathinfo( $view_filename, PATHINFO_DIRNAME ) != $conf['views_dir'] ) {
        die('Invalid path detected');
      }