Denial of Service (DoS) via DoS-prone BigDecimal parsing of scientific notation in NumberConverter
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