From 1913ccadfa61f758e72cf4452ea4f7c04ce850cd Mon Sep 17 00:00:00 2001 From: Sony Mathew Date: Tue, 19 May 2026 20:39:40 +0530 Subject: [PATCH] fix: [CW-7141] fix gem audit issue for sidekiq-cron and devise (#14497) # Pull Request Template ## Description * sidekiq-cron upgraded to 2.4.0 * Sidekiq constrained to stay on 7.3.x * Devise advisory ignored in .bundler-audit.yml with the reason: Chatwoot does not enable Timeoutable, so the timeout redirect path is not reachable ### Details The sidekiq-cron upgrade is from 1.12.0 to 2.4.0. What changed that matters for us: Fixes the reported Sidekiq Web UI reflected XSS in 2.4.0. Adds namespace handling changes from the 2.x series. Chatwoot does not use custom cron namespaces in config/schedule.yml, so the migration guide says no action is needed for our usage. Drops support for old Sidekiq/Redis versions. We are still on Sidekiq 7.3.1, which is supported. Adds new dependencies: cronex and unicode. Keeps the same APIs we use: Sidekiq::Cron::Job.load_from_hash!(schedule, source: 'schedule'), Sidekiq::Cron::Job.destroy(name), and require 'sidekiq/cron/web' still exist. Chance of breakage: low, based on the current Chatwoot usage. The main thing I would watch after deploy is scheduled job registration in Sidekiq. The one subtle area is namespace behavior: if production has custom, manually-created cron jobs using non-default namespaces, load_from_hash! cleanup behavior could matter. For the committed config/schedule.yml jobs, which do not specify namespaces, they should continue in the default namespace. For concerns around Devise, it does not look exploitable in current Chatwoot, because Chatwoot does not enable Devise :timeoutable. I checked: app/models/user.rb (line 59) lists the Devise modules, and :timeoutable is not included. config/initializers/devise.rb (line 164) has the timeoutable section, but config.timeout_in is commented out. SuperAdmin inherits from User, so it does not add a separate timeoutable path either. So from a practical security perspective: the vulnerable redirect path requires warden_message == :timeout, which is only produced by Devise Timeoutable. Since Chatwoot does not use Timeoutable, this warning is not currently reachable. Is the patch really needed? Strictly for current exploitability: no. Fixes #CW-7141 ## Type of change Please delete options that are not relevant. - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality not to work as expected) - [ ] This change requires a documentation update ## How Has This Been Tested? Spec and lints and change-log checks with codex. ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [ ] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules Co-authored-by: Vishnu Narayanan --- .bundler-audit.yml | 3 +++ Gemfile | 4 ++-- Gemfile.lock | 15 ++++++++++----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.bundler-audit.yml b/.bundler-audit.yml index 0a6c574abf8..ffbfa18e054 100644 --- a/.bundler-audit.yml +++ b/.bundler-audit.yml @@ -2,6 +2,9 @@ ignore: - CVE-2021-41098 # https://github.com/chatwoot/chatwoot/issues/3097 (update once azure blob storage is updated) - GHSA-57hq-95w6-v4fc # Devise confirmable race condition — patched locally in User model (remove once on Devise 5+) + # Devise 5 is currently blocked by devise-secure_password/devise_token_auth/devise-two-factor. + # Chatwoot does not enable Timeoutable, so the timeout redirect path is not reachable. + - GHSA-jp94-3292-c3xv # Rails 7.1 has no patched release for the Active Storage proxy range # advisories. Chatwoot limits proxy range requests locally. - CVE-2026-33658 diff --git a/Gemfile b/Gemfile index dfcdb3e3084..b27b66fde30 100644 --- a/Gemfile +++ b/Gemfile @@ -133,9 +133,9 @@ gem 'sentry-ruby', require: false gem 'sentry-sidekiq', '>= 5.19.0', require: false ##-- background job processing --## -gem 'sidekiq', '>= 7.3.1' +gem 'sidekiq', '~> 7.3', '>= 7.3.1' # We want cron jobs -gem 'sidekiq-cron', '>= 1.12.0' +gem 'sidekiq-cron', '>= 2.4.0' # for sidekiq healthcheck gem 'sidekiq_alive' diff --git a/Gemfile.lock b/Gemfile.lock index 21dfd3547f3..ed1d94172e0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -196,6 +196,9 @@ GEM bigdecimal rexml crass (1.0.6) + cronex (0.15.0) + tzinfo + unicode (>= 0.4.4.5) csv (3.3.0) csv-safe (3.3.1) csv (~> 3.0) @@ -902,10 +905,11 @@ GEM logger rack (>= 2.2.4) redis-client (>= 0.22.2) - sidekiq-cron (1.12.0) - fugit (~> 1.8) + sidekiq-cron (2.4.0) + cronex (>= 0.13.0) + fugit (~> 1.8, >= 1.11.1) globalid (>= 1.0.1) - sidekiq (>= 6) + sidekiq (>= 6.5.0) sidekiq_alive (2.5.0) gserver (~> 0.0.1) sidekiq (>= 5, < 9) @@ -979,6 +983,7 @@ GEM unf (0.1.4) unf_ext unf_ext (0.0.8.2) + unicode (0.4.4.5) unicode-display_width (3.1.4) unicode-emoji (~> 4.0, >= 4.0.4) unicode-emoji (4.0.4) @@ -1155,8 +1160,8 @@ DEPENDENCIES sentry-sidekiq (>= 5.19.0) shopify_api shoulda-matchers - sidekiq (>= 7.3.1) - sidekiq-cron (>= 1.12.0) + sidekiq (~> 7.3, >= 7.3.1) + sidekiq-cron (>= 2.4.0) sidekiq_alive simplecov (>= 0.21) simplecov_json_formatter