Denial of Service (DoS) via DoS-prone BigDecimal parsing of scientific notation in NumberConverter

HIGH
rails/rails
Commit: 64fabbd33c6e
Affected: Rails 8.1.x prior to this fix (e.g., 8.1.0 - 8.1.2)
2026-04-05 12:20 UTC

Description

The commit patches ActiveSupport::NumberHelper::NumberConverter to reject strings containing scientific notation (digits followed by e or d, case-insensitive) when converting to BigDecimal. Previously, number inputs using scientific notation (e.g., "9e1000000" or similar) could be parsed by BigDecimal(number, exception: false), which can incur extreme resource usage (CPU/memory) and lead to denial-of-service conditions. The fix guards against such inputs by skipping BigDecimal parsing when the string matches /[de]/i. This aligns with the referenced CVE-2026-33176 and GHSA-2j26-frm8-cmj9, and the tests added in the patch validate that scientific notation inputs are treated as non-numeric rather than parsed as BigDecimal. Vulnerability type: Denial of Service (DoS) via input validation / BigDecimal parsing of scientific notation in NumberConverter. Affected code: activesupport/lib/active_support/number_helper/number_converter.rb (valid_bigdecimal) and related tests (activesupport/test/number_helper_test.rb).

Proof of Concept

# Proof-of-concept demonstrating potential DoS before fix # This PoC shows how a string using scientific notation could cause heavy parsing work in NumberConverter. # Prerequisites: Rails environment with this vulnerability (pre-fix) in ActiveSupport::NumberHelper. # Run in Rails console or a small Ruby script that loads ActiveSupport and uses number_to_currency with a scientific notation string. require 'active_support/all' include ActiveSupport::NumberHelper input = "9e1000000" # extremely large exponent in scientific notation start_time = Time.now 10.times do number_to_currency(input) end puts "Elapsed (DoS test, pre-fix expectation): #{Time.now - start_time} seconds" # In a vulnerable environment, this could consume excessive CPU/memory. With the patch, inputs containing 'e' would skip BigDecimal parsing and be handled safely.

Commit Details

Author: Jean Boussier

Date: 2025-06-11 15:48 UTC

Message:

NumberConverter: reject scientific notation BigDecimal support scientific notation, which allow expressing extremly large numbers with just a few bytes of input. This could be exploited to DOS a service if somehow user input is passed to number converter. [CVE-2026-33176] [GHSA-2j26-frm8-cmj9]

Triage Assessment

Vulnerability Type: Denial of Service (DoS) / Input validation issue

Confidence: HIGH

Reasoning:

Commit blocks scientific notation input to BigDecimal in NumberConverter to prevent potential DoS via extremely large numbers represented compactly. It references CVE-2026-33176 and GHSA-2j26-frm8-cmj9 and adds tests for scientific notation handling, indicating a vulnerability fix related to input validation that could lead to resource exhaustion.

Verification Assessment

Vulnerability Type: Denial of Service (DoS) via DoS-prone BigDecimal parsing of scientific notation in NumberConverter

Confidence: HIGH

Affected Versions: Rails 8.1.x prior to this fix (e.g., 8.1.0 - 8.1.2)

Code Diff

diff --git a/activesupport/lib/active_support/number_helper/number_converter.rb b/activesupport/lib/active_support/number_helper/number_converter.rb index a68838c0ee544..8ea0a907a39f9 100644 --- a/activesupport/lib/active_support/number_helper/number_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_converter.rb @@ -180,7 +180,7 @@ def valid_bigdecimal when Float, Rational number.to_d(0) when String - BigDecimal(number, exception: false) + BigDecimal(number, exception: false) unless number.to_s.match?(/[de]/i) else number.to_d rescue nil end diff --git a/activesupport/test/number_helper_test.rb b/activesupport/test/number_helper_test.rb index 1dfb09bcff050..bae6a9eb2261e 100644 --- a/activesupport/test/number_helper_test.rb +++ b/activesupport/test/number_helper_test.rb @@ -456,6 +456,18 @@ def test_number_helpers_should_return_non_numeric_param_unchanged assert_equal "x", number_helper.number_to_human("x") end end + + def test_number_helpers_with_scientific_notation + [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| + assert_equal "$123481223d98989", number_helper.number_to_currency("123481223d98989") + assert_equal "$11288E822220222", number_helper.number_to_currency("11288E822220222") + assert_equal "-$888E89789", number_helper.number_to_currency("-888E89789") + + assert_equal "123481223d98989%", number_helper.number_to_percentage("123481223d98989") + assert_equal "11288E822220222%", number_helper.number_to_percentage("11288E822220222") + assert_equal "-888E89789%", number_helper.number_to_percentage("-888E89789") + end + end end end end
← Back to Alerts View on GitHub →