From ff2d7f71d85bc6c951f8caeb7763e105dcfc19b7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Mar 2026 04:38:09 +0000 Subject: [PATCH 1/5] Bump yaml in the npm_and_yarn group across 1 directory Bumps the npm_and_yarn group with 1 update in the / directory: [yaml](https://github.com/eemeli/yaml). Updates `yaml` from 2.3.4 to 2.8.3 - [Release notes](https://github.com/eemeli/yaml/releases) - [Commits](https://github.com/eemeli/yaml/compare/v2.3.4...v2.8.3) --- updated-dependencies: - dependency-name: yaml dependency-version: 2.8.3 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4c10751..e5a7b35 100644 --- a/yarn.lock +++ b/yarn.lock @@ -815,9 +815,9 @@ yallist@^4.0.0: integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== yaml@^2.3.4: - version "2.3.4" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2" - integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA== + version "2.8.3" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.3.tgz#a0d6bd2efb3dd03c59370223701834e60409bd7d" + integrity sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg== yargs-parser@^21.1.1: version "21.1.1" From ec6dc9ebe1ab64e4dea92619d1be23e7ed72457d Mon Sep 17 00:00:00 2001 From: rsmokeUM Date: Tue, 31 Mar 2026 10:46:13 -0400 Subject: [PATCH 2/5] Add parameter sanitization to ApplicationController Implemented a before_action to strip null bytes from request parameters, enhancing security and data integrity. Introduced methods to recursively sanitize strings, arrays, hashes, and ActionController::Parameters, ensuring all incoming data is clean before processing. --- app/controllers/application_controller.rb | 23 ++++++++++++ spec/requests/user_sessions_spec.rb | 43 +++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 spec/requests/user_sessions_spec.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 4f1d7e0..60e6882 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,6 +1,29 @@ class ApplicationController < ActionController::Base + before_action :strip_null_bytes_from_params + private + def strip_null_bytes_from_params + sanitize_param_object!(request.request_parameters) if request.request_parameters.present? + sanitize_param_object!(request.query_parameters) if request.query_parameters.present? + sanitize_param_object!(params) + end + + def sanitize_param_object!(value) + case value + when String + value.delete("\u0000") + when Array + value.map! { |item| sanitize_param_object!(item) } + when ActionController::Parameters + value.each_pair { |key, item| value[key] = sanitize_param_object!(item) } + when Hash + value.each { |key, item| value[key] = sanitize_param_object!(item) } + else + value + end + end + def current_application_settings @current_application_settings ||= ApplicationSetting.get_current_app_settings end diff --git a/spec/requests/user_sessions_spec.rb b/spec/requests/user_sessions_spec.rb new file mode 100644 index 0000000..23bbb3a --- /dev/null +++ b/spec/requests/user_sessions_spec.rb @@ -0,0 +1,43 @@ +require 'rails_helper' + +RSpec.describe 'User sessions', type: :request do + describe 'POST /users/sign_in' do + let(:user) { create(:user) } + let(:email_with_null_byte) { "#{user.email}\u0000" } + it 'sanitizes null bytes in login params and does not raise an error' do + expect do + post user_session_path, params: { + user: { + email: email_with_null_byte, + password: user.password + } + } + end.not_to raise_error + + expect(response).to have_http_status(:see_other) + expect(response).to redirect_to(root_path) + end + + it 'sanitizes null bytes recursively in nested params and arrays' do + nested_params = { + user: { + email: "#{user.email}\u0000", + password: "pass\u0000word123", + metadata: { + tags: ["alp\u0000ha", "be\u0000ta"], + profile: { + nickname: "ni\u0000ck" + } + } + } + } + + expect do + post user_session_path, params: nested_params + end.not_to raise_error + + expect(response).to have_http_status(:see_other) + expect(response).to redirect_to(root_path) + end + end +end From 464b8297c233c2e9faec604046a5261d4eb9d8c0 Mon Sep 17 00:00:00 2001 From: rsmokeUM Date: Tue, 31 Mar 2026 10:49:55 -0400 Subject: [PATCH 3/5] Add request specs for user registration with null byte sanitization Implemented tests to ensure that user registration handles null bytes in parameters correctly. The specs verify that null bytes are sanitized without raising errors and that the user is successfully created, both for flat and nested payloads. This enhances the robustness of user input handling in the registration process. --- spec/requests/user_registrations_spec.rb | 48 ++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 spec/requests/user_registrations_spec.rb diff --git a/spec/requests/user_registrations_spec.rb b/spec/requests/user_registrations_spec.rb new file mode 100644 index 0000000..e2743b1 --- /dev/null +++ b/spec/requests/user_registrations_spec.rb @@ -0,0 +1,48 @@ +require 'rails_helper' + +RSpec.describe 'User registrations', type: :request do + describe 'POST /users' do + let(:base_email) { "new_user_#{SecureRandom.hex(4)}@example.com" } + let(:password) { 'password123' } + + it 'sanitizes null bytes in registration params and does not raise an error' do + expect do + post user_registration_path, params: { + user: { + email: "#{base_email}\u0000", + password: "pass\u0000word123", + password_confirmation: "pass\u0000word123" + } + } + end.not_to raise_error + + expect(response).to have_http_status(:see_other) + expect(response).to redirect_to(root_path) + expect(User.exists?(email: base_email)).to be(true) + end + + it 'sanitizes null bytes recursively for nested registration payloads' do + nested_params = { + user: { + email: "#{base_email}\u0000", + password: "pass\u0000word123", + password_confirmation: "pass\u0000word123", + metadata: { + tags: ["fir\u0000st", "sec\u0000ond"], + profile: { + nickname: "ni\u0000ck" + } + } + } + } + + expect do + post user_registration_path, params: nested_params + end.not_to raise_error + + expect(response).to have_http_status(:see_other) + expect(response).to redirect_to(root_path) + expect(User.exists?(email: base_email)).to be(true) + end + end +end From a1a0487689aac515eef1e9692b899e4fa8810718 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Mar 2026 14:53:53 +0000 Subject: [PATCH 4/5] Bump the npm_and_yarn group across 1 directory with 2 updates Bumps the npm_and_yarn group with 2 updates in the / directory: [brace-expansion](https://github.com/juliangruber/brace-expansion) and [picomatch](https://github.com/micromatch/picomatch). Updates `brace-expansion` from 1.1.12 to 1.1.13 - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.12...v1.1.13) Updates `picomatch` from 2.3.1 to 2.3.2 - [Release notes](https://github.com/micromatch/picomatch/releases) - [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2) --- updated-dependencies: - dependency-name: brace-expansion dependency-version: 1.1.13 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: picomatch dependency-version: 2.3.2 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] --- yarn.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index e5a7b35..324735b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -239,9 +239,9 @@ bootstrap@^5.3.3: integrity sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg== brace-expansion@^1.1.7: - version "1.1.12" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843" - integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== + version "1.1.13" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.13.tgz#d37875c01dc9eff988dd49d112a57cb67b54efe6" + integrity sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" @@ -594,9 +594,9 @@ picocolors@^1.0.0: integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + version "2.3.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.2.tgz#5a942915e26b372dc0f0e6753149a16e6b1c5601" + integrity sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA== pify@^2.3.0: version "2.3.0" From 2e7a50952a03542969f6e7ce75d1173f9b317dd2 Mon Sep 17 00:00:00 2001 From: rsmokeUM Date: Tue, 31 Mar 2026 11:21:22 -0400 Subject: [PATCH 5/5] Add request spec for null byte sanitization in user sessions Implemented a test to ensure that null bytes in passwords are sanitized during user authentication. The test verifies that no errors are raised and that the user is redirected appropriately after login. This enhances the security of user session handling by ensuring that null bytes do not disrupt the authentication process. --- app/controllers/application_controller.rb | 21 ++++++++++++++++----- spec/requests/user_sessions_spec.rb | 14 ++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 60e6882..5bd3dc0 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -4,9 +4,7 @@ class ApplicationController < ActionController::Base private def strip_null_bytes_from_params - sanitize_param_object!(request.request_parameters) if request.request_parameters.present? - sanitize_param_object!(request.query_parameters) if request.query_parameters.present? - sanitize_param_object!(params) + sanitize_param_object!(request.parameters) if request.parameters.present? end def sanitize_param_object!(value) @@ -16,9 +14,22 @@ def sanitize_param_object!(value) when Array value.map! { |item| sanitize_param_object!(item) } when ActionController::Parameters - value.each_pair { |key, item| value[key] = sanitize_param_object!(item) } + # Sanitize both keys and values. + value.keys.each do |key| + item = value.delete(key) + sanitized_key = key.to_s.delete("\u0000") + value[sanitized_key] = sanitize_param_object!(item) + end + value when Hash - value.each { |key, item| value[key] = sanitize_param_object!(item) } + # Sanitize both keys and values, preserving Symbol keys. + value.keys.each do |key| + item = value.delete(key) + sanitized_key_string = key.to_s.delete("\u0000") + sanitized_key = key.is_a?(Symbol) ? sanitized_key_string.to_sym : sanitized_key_string + value[sanitized_key] = sanitize_param_object!(item) + end + value else value end diff --git a/spec/requests/user_sessions_spec.rb b/spec/requests/user_sessions_spec.rb index 23bbb3a..cb2f18c 100644 --- a/spec/requests/user_sessions_spec.rb +++ b/spec/requests/user_sessions_spec.rb @@ -39,5 +39,19 @@ expect(response).to have_http_status(:see_other) expect(response).to redirect_to(root_path) end + + it 'sanitizes null bytes in password before authentication' do + expect do + post user_session_path, params: { + user: { + email: user.email, + password: "pass\u0000word123" + } + } + end.not_to raise_error + + expect(response).to have_http_status(:see_other) + expect(response).to redirect_to(root_path) + end end end