From 95d6aecb519b9330b251eb59bb1da4306d3ec9d2 Mon Sep 17 00:00:00 2001 From: Adam Berger <132088347+Sneaky-Goat-Dev@users.noreply.github.com> Date: Thu, 11 Jun 2026 12:43:57 +0200 Subject: [PATCH] chore: Add security flags to session cookie configuration (#14248) ## Summary - Adds `httponly` and `secure` flags to session cookie configuration - Adds RSpec tests for session configuration ## Changes - `config/initializers/session_store.rb`: add `httponly: true`, `secure: FORCE_SSL` - `spec/config/session_store_spec.rb`: tests for all session store options Ref #2683 (hardens the session cookie but does not remove it, sessions are still needed for super_admin dashboard) --------- Co-authored-by: Adam-Relay Co-authored-by: Adam Berger Co-authored-by: Vishnu Narayanan --- config/initializers/session_store.rb | 9 ++++++++- spec/config/session_store_spec.rb | 29 ++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 spec/config/session_store_spec.rb diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb index 9d0d1f35b..6e6ce8134 100644 --- a/config/initializers/session_store.rb +++ b/config/initializers/session_store.rb @@ -1,3 +1,10 @@ # Be sure to restart your server when you modify this file. +# Sessions are used only for the super_admin dashboard (flash/CSRF), not for API auth. -Rails.application.config.session_store :cookie_store, key: '_chatwoot_session', same_site: :lax +secure_cookies = ActiveModel::Type::Boolean.new.cast(ENV.fetch('FORCE_SSL', false)) + +Rails.application.config.session_store :cookie_store, + key: '_chatwoot_session', + same_site: :lax, + secure: secure_cookies, + httponly: true diff --git a/spec/config/session_store_spec.rb b/spec/config/session_store_spec.rb new file mode 100644 index 000000000..a4f74af52 --- /dev/null +++ b/spec/config/session_store_spec.rb @@ -0,0 +1,29 @@ +require 'rails_helper' + +# rubocop:disable RSpec/DescribeClass +describe 'Session Store Configuration' do + # rubocop:enable RSpec/DescribeClass + + let(:session_options) { Rails.application.config.session_options } + + it 'uses cookie_store as the session store' do + expect(Rails.application.config.session_store).to eq(ActionDispatch::Session::CookieStore) + end + + it 'sets the session key' do + expect(session_options[:key]).to eq('_chatwoot_session') + end + + it 'sets same_site to lax' do + expect(session_options[:same_site]).to eq(:lax) + end + + it 'sets httponly to true' do + expect(session_options[:httponly]).to be(true) + end + + it 'sets secure flag based on FORCE_SSL' do + expected_secure = ActiveModel::Type::Boolean.new.cast(ENV.fetch('FORCE_SSL', false)) + expect(session_options[:secure]).to eq(expected_secure) + end +end