CVE-2023-50725: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Resque is a Redis-backed Ruby library for creating background jobs, placing them on multiple queues, and processing them later. The following paths in resque-web have been found to be vulnerable to reflected XSS: "/failed/?class=<script>alert(document.cookie)</script>" and "/queues/><img src=a onerror=alert(document.cookie)>". This issue has been patched in version 2.2.1.
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.
CVSS v3 base score: 6.1
Published: 2023-12-22T20:15Z
Repository: https://github.com/resque/resque
Language: Ruby
Files changed: lib/resque/server/views/error.erb, lib/resque/server/views/failed.erb, lib/resque/server/views/key_string.erb, lib/resque/server/views/queues.erb
Commit date: 2022-03-27 09:45:38 -0600
Commit message: Escape HTML from the params to avoid XSS (#1790)

* Escape HTML from the params to avoid XSS

* Only escape the param when it's printed to the DOM
Diff: diff --git a/lib/resque/server/views/error.erb b/lib/resque/server/views/error.erb
index 05bc5a7..725554b 100644
--- a/lib/resque/server/views/error.erb
+++ b/lib/resque/server/views/error.erb
@@ -1 +1 @@
-<h1 style="font-size:110%;font-family:Arial, sans-serif;"><%= error %></h1>
\ No newline at end of file
+<h1 style="font-size:110%;font-family:Arial, sans-serif;"><%= escape_html(error) %></h1>
diff --git a/lib/resque/server/views/failed.erb b/lib/resque/server/views/failed.erb
index 37af373..adb569c 100644
--- a/lib/resque/server/views/failed.erb
+++ b/lib/resque/server/views/failed.erb
@@ -1,23 +1,23 @@
 <% if failed_multiple_queues? && !params[:queue] %>
 <h1>All Failed Queues: <%= Resque::Failure.queues.size %> total</h1>
 <% else %>
-<h1>Failed Jobs <%= "on '#{params[:queue]}'" if params[:queue] %> <%= "with class '#{params[:class]}'" if params[:class] %></h1>
+<h1>Failed Jobs <%= "on '#{escape_html(params[:queue])}'" if params[:queue] %> <%= "with class '#{escape_html(params[:class])}'" if params[:class] %></h1>
 <% end %>
 
 <% unless failed_size.zero? %>
 <form method="POST" action="<%= u "failed#{'/' + params[:queue] if params[:queue]}/clear" %>">
-  <input type="submit" name="" value="Clear <%= params[:queue] ? "'#{params[:queue]}'" : 'Failed' %> Jobs" class="confirmSubmission" />
+  <input type="submit" name="" value="Clear <%= params[:queue] ? "'#{escape_html(params[:queue])}'" : 'Failed' %> Jobs" class="confirmSubmission" />
 </form>
 
 <% unless params[:queue] %>
   <form method="POST" action="<%= u "failed/clear_retried" %>">
     <input type="submit" name="" value="Clear Retried Jobs" onclick='return confirm("Are you absolutely sure? This cannot be undone.");' />
   </form>
 <% end %>
 <form method="POST" action="<%= u "failed#{'/' + params[:queue] if params[:queue]}/requeue/all" %>">
-  <input type="submit" name="" value="Retry <%= params[:queue] ? "'#{params[:queue]}'" : 'Failed' %> Jobs" class="confirmSubmission" />
+  <input type="submit" name="" value="Retry <%= params[:queue] ? "'#{escape_html(params[:queue])}'" : 'Failed' %> Jobs" class="confirmSubmission" />
 </form>
 <% end %>
 
 <% if failed_multiple_queues? && !params[:queue] %>
 <%= partial :failed_queues_overview %>
diff --git a/lib/resque/server/views/key_string.erb b/lib/resque/server/views/key_string.erb
index 4bd3e93..d9d103a 100644
--- a/lib/resque/server/views/key_string.erb
+++ b/lib/resque/server/views/key_string.erb
@@ -1,7 +1,7 @@
 <% if key = params[:key] %>
-  <h1>Key "<%= key %>" is a <%= resque.redis.type key %></h1>
+  <h1>Key "<%= escape_html(key) %>" is a <%= resque.redis.type key %></h1>
   <h2>size: <%= redis_get_size(key) %></h2>
   <table>
     <tr>
       <td>
         <%= redis_get_value_as_array(key) %>
diff --git a/lib/resque/server/views/queues.erb b/lib/resque/server/views/queues.erb
index ea8a63d..9b6c720 100644
--- a/lib/resque/server/views/queues.erb
+++ b/lib/resque/server/views/queues.erb
@@ -1,10 +1,10 @@
 <% @subtabs = resque.queues unless partial? || params[:id].nil? %>
 
 <% if current_queue = params[:id] %>
 
-  <h1>Pending jobs on <span class='hl'><%= h current_queue %></span></h1>
+  <h1>Pending jobs on <span class='hl'><%= h escape_html(current_queue) %></span></h1>
   <form method="POST" action="<%=u "/queues/#{current_queue}/remove" %>" class='remove-queue'>
     <input type='submit' name='' value='Remove Queue' class="confirmSubmission" />
   </form>
   <p class='sub'><%= page_entries_info start = params[:start].to_i, start + 19, size = resque.size(current_queue), 'job' %></p>
   <table class='jobs'>

Vulnerable code: <h1 style="font-size:110%;font-family:Arial, sans-serif;"><%= error %></h1>
<h1>Failed Jobs <%= "on '#{params[:queue]}'" if params[:queue] %> <%= "with class '#{params[:class]}'" if params[:class] %></h1>
  <input type="submit" name="" value="Clear <%= params[:queue] ? "'#{params[:queue]}'" : 'Failed' %> Jobs" class="confirmSubmission" />
  <input type="submit" name="" value="Retry <%= params[:queue] ? "'#{params[:queue]}'" : 'Failed' %> Jobs" class="confirmSubmission" />
  <h1>Key "<%= key %>" is a <%= resque.redis.type key %></h1>
  <h1>Pending jobs on <span class='hl'><%= h current_queue %></span></h1>
Fixed code: <h1 style="font-size:110%;font-family:Arial, sans-serif;"><%= escape_html(error) %></h1>
<h1>Failed Jobs <%= "on '#{escape_html(params[:queue])}'" if params[:queue] %> <%= "with class '#{escape_html(params[:class])}'" if params[:class] %></h1>
  <input type="submit" name="" value="Clear <%= params[:queue] ? "'#{escape_html(params[:queue])}'" : 'Failed' %> Jobs" class="confirmSubmission" />
  <input type="submit" name="" value="Retry <%= params[:queue] ? "'#{escape_html(params[:queue])}'" : 'Failed' %> Jobs" class="confirmSubmission" />
  <h1>Key "<%= escape_html(key) %>" is a <%= resque.redis.type key %></h1>
  <h1>Pending jobs on <span class='hl'><%= h escape_html(current_queue) %></span></h1>