Vulnerability: Revive Adserver before v5.2.0 is vulnerable to a reflected XSS vulnerability in the `status` parameter of campaign-zone-zones.php. An attacker could trick a user with access to the user interface of a Revive Adserver instance into clicking on a specifically crafted URL and execute injected JavaScript code.
Vulnerability ID: CVE-2021-22888
CWE: CWE-79
Severity score: 2.9
Project: https://github.com/revive-adserver/revive-adserver
Published: 2021-03-25
File: lib/templates/admin/campaign-zone-zones.html
Commit message: Fix h1 report 1097979
Commit author: Matteo Beccati

Vulnerable version (before fix):
 {/if}   <!--rows-{$status}-start--> {if !empty($topPager->links)} <span id="page-{$status}" class="hide">{$page}</span> <div class="tableWrapper topPagerContainer clearfix">   <div class="pager topPager">     {$topPager->links}   </div> </div> {/if} <table id="zones-{$status}" class="zones new-table tableWrapper">   <tbody>     <tr class="header hide">       <th class="name"><label><input type="checkbox" id="{$status}-select-all" class="checkbox select-all" /> {t str=SelectUnselectAll}</label></th>       <th class="link"></th>       {if !empty($showStats)}           <th class="ctr">{t str=FinanceCTR}</th>   </tbody>    {if !empty($topPager->links)}   <tbody id="select-all-container-{$status}" class="hide">     <tr class="header">       <th colspan="{$colspan}">         <div id="zones-{$status}-select-all" class="selectAllInAccount hide">           All <em>{$zonescounts.showing}</em> zones on this page selected. <a href="#">Select all <em>{$zonescounts.matching}</em> matching zones from this account.</a>         </div>         <div id="zones-{$status}-all-selected" class="selectAllInAccount hide">           All <em>{$zonescounts.matching}</em> matching zones from this account selected. <a href="#">Clear selection</a></a>         </div>       </th>     </tr>   </tbody>   {/if}    <tbody id="zones-{$status}-rows">     {foreach from=$websites key=websiteid item=website}     <tr class="website">       <td class="name" title="{$website.name|escape}">   {/if}  </table> <!--rows-{$status}-end-->  <!--status-{$status}-start-->   {if $status == 'linked'}   {t str=Linked}:   {else}   <span class="status-value">{$zonescounts.all}</span><br />    {t str=Showing}: <span class="status-value">{$zonescounts.showing}</span> <!--status-{$status}-end-->

Fixed version (after fix):
 {/if}   <!--rows-{$status|escape}-start--> {if !empty($topPager->links)} <span id="page-{$status|escape}" class="hide">{$page}</span> <div class="tableWrapper topPagerContainer clearfix">   <div class="pager topPager">     {$topPager->links}   </div> </div> {/if} <table id="zones-{$status|escape}" class="zones new-table tableWrapper">   <tbody>     <tr class="header hide">       <th class="name"><label><input type="checkbox" id="{$status|escape}-select-all" class="checkbox select-all" /> {t str=SelectUnselectAll}</label></th>       <th class="link"></th>       {if !empty($showStats)}           <th class="ctr">{t str=FinanceCTR}</th>   </tbody>    {if !empty($topPager->links)}   <tbody id="select-all-container-{$status|escape}" class="hide">     <tr class="header">       <th colspan="{$colspan}">         <div id="zones-{$status|escape}-select-all" class="selectAllInAccount hide">           All <em>{$zonescounts.showing}</em> zones on this page selected. <a href="#">Select all <em>{$zonescounts.matching}</em> matching zones from this account.</a>         </div>         <div id="zones-{$status|escape}-all-selected" class="selectAllInAccount hide">           All <em>{$zonescounts.matching}</em> matching zones from this account selected. <a href="#">Clear selection</a></a>         </div>       </th>     </tr>   </tbody>   {/if}    <tbody id="zones-{$status|escape}-rows">     {foreach from=$websites key=websiteid item=website}     <tr class="website">       <td class="name" title="{$website.name|escape}">   {/if}  </table> <!--rows-{$status|escape}-end-->  <!--status-{$status|escape}-start-->   {if $status == 'linked'}   {t str=Linked}:   {else}   <span class="status-value">{$zonescounts.all}</span><br />    {t str=Showing}: <span class="status-value">{$zonescounts.showing}</span> <!--status-{$status|escape}-end-->

Patch:
patch: @@ -16,19 +16,19 @@
 {/if}
 
 
-<!--rows-{$status}-start-->
+<!--rows-{$status|escape}-start-->
 {if !empty($topPager->links)}
-<span id="page-{$status}" class="hide">{$page}</span>
+<span id="page-{$status|escape}" class="hide">{$page}</span>
 <div class="tableWrapper topPagerContainer clearfix">
   <div class="pager topPager">
     {$topPager->links}
   </div>
 </div>
 {/if}
-<table id="zones-{$status}" class="zones new-table tableWrapper">
+<table id="zones-{$status|escape}" class="zones new-table tableWrapper">
   <tbody>
     <tr class="header hide">
-      <th class="name"><label><input type="checkbox" id="{$status}-select-all" class="checkbox select-all" /> {t str=SelectUnselectAll}</label></th>
+      <th class="name"><label><input type="checkbox" id="{$status|escape}-select-all" class="checkbox select-all" /> {t str=SelectUnselectAll}</label></th>
       <th class="link"></th>
       {if !empty($showStats)}
           <th class="ctr">{t str=FinanceCTR}</th>
@@ -39,21 +39,21 @@
   </tbody>
 
   {if !empty($topPager->links)}
-  <tbody id="select-all-container-{$status}" class="hide">
+  <tbody id="select-all-container-{$status|escape}" class="hide">
     <tr class="header">
       <th colspan="{$colspan}">
-        <div id="zones-{$status}-select-all" class="selectAllInAccount hide">
+        <div id="zones-{$status|escape}-select-all" class="selectAllInAccount hide">
           All <em>{$zonescounts.showing}</em> zones on this page selected. <a href="#">Select all <em>{$zonescounts.matching}</em> matching zones from this account.</a>
         </div>
-        <div id="zones-{$status}-all-selected" class="selectAllInAccount hide">
+        <div id="zones-{$status|escape}-all-selected" class="selectAllInAccount hide">
           All <em>{$zonescounts.matching}</em> matching zones from this account selected. <a href="#">Clear selection</a></a>
         </div>
       </th>
     </tr>
   </tbody>
   {/if}
 
-  <tbody id="zones-{$status}-rows">
+  <tbody id="zones-{$status|escape}-rows">
     {foreach from=$websites key=websiteid item=website}
     <tr class="website">
       <td class="name" title="{$website.name|escape}">
@@ -125,9 +125,9 @@
   {/if}
 
 </table>
-<!--rows-{$status}-end-->
+<!--rows-{$status|escape}-end-->
 
-<!--status-{$status}-start-->
+<!--status-{$status|escape}-start-->
   {if $status == 'linked'}
   {t str=Linked}:
   {else}
@@ -136,4 +136,4 @@
   <span class="status-value">{$zonescounts.all}</span><br />
 
   {t str=Showing}: <span class="status-value">{$zonescounts.showing}</span>
-<!--status-{$status}-end-->
+<!--status-{$status|escape}-end-->
path: lib/templates/admin/campaign-zone-zones.html