CVE-2026-126351: Addressable: Denial of service in URI path normalization
Impact
Addressable::URI.normalizepath takes time quadratic in the number of nested dot segments in a path (e.g., "/" + "a/" n + "../" n, which for n = 3 is /a/a/a/../../../), because it removes one dot segment per pass over the whole path. URI#normalize, URI#normalizedpath, URI#==, URI#=== and URI#join all call it. Normalizing, comparing or joining a URI taken from user input can result in uncontrolled resource consumption, leading to denial of service. On 2.9.0, normalizing a 34 KB path takes about 3.5 seconds on MRI Ruby 4.0, and the cost grows with the square of the path length.
This affects every Ruby implementation, including MRI Ruby 3.2 and later. URI.parse by itself is unaffected, as is code that never normalizes, compares, or joins URIs from untrusted sources.
Affected Versions
This vulnerability affects all versions of Addressable prior to 2.9.1. It is fixed in 2.9.1.
Workarounds
- Limit the length of URIs taken from user input before calling normalize, == or join on them. Web servers often limit request lines to about 8 KB, which keeps the cost to about 150 milliseconds per call on typical hardware, but URIs from other sources (request bodies, headers such as Location, stored data) may not be limited. - Reject paths with many dot segments before normalizing them.
Credits
Reported by Matthew Mongeau (@halogenandtoast), Ruby Central Gem Security, who also suggested the single-pass approach used in the fix.
For more information
If there are any questions or comments about this advisory: Open an issue
Other sources
Addressable is an alternative implementation to the URI implementation that is part of Ruby's standard library. Prior to 2.9.1, Addressable::URI.normalizepath repeatedly scans and rewrites paths while removing only one nested dot segment per pass, producing quadratic work. URI#normalize, URI#normalizedpath, URI#join, URI#==, and URI#=== inherit the behavior, so processing a sufficiently long attacker-controlled URI can consume a worker thread and cause denial of service on every Ruby implementation. URI.parse alone and code that never normalizes, compares, or joins untrusted URIs are unaffected. This issue is fixed in version 2.9.1.
— MITRE
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
rubygems/addressableto a version that resolves this vulnerability.Fixed in 2.9.1 - Upgrade
Upgrade
Addressableto a version that resolves this vulnerability.Fixed in 2.9.1 - Compensating control
Limit the length of URIs taken from user input before calling normalize, ==, or join on them.
- Compensating control
Reject paths with many dot segments before normalizing them.
Event History
Frequently Asked Questions
Which applications are exposed to this issue?
Applications using Addressable versions earlier than 2.9.1 are affected if they normalize, compare, or join URIs originating from untrusted input. URI.parse alone is not affected, and code that never performs those operations on untrusted URIs is not exposed.
What does an attacker need to send to trigger excessive resource consumption?
An attacker needs to supply a URI path with many nested dot segments, such as repeated path components followed by repeated ../ segments, to a code path that calls normalize, normalized_path, ==, ===, or join. No privileges or user interaction are required, but constructing an effective path requires high attack complexity.
What can be done before upgrading?
Limit the length of user-supplied URIs before calling normalize, ==, or join. Request-line limits around 8 KB typically keep normalization to about 150 milliseconds per call on typical hardware, though URIs received from sources other than web request lines may need separate limits.
What version resolves the issue?
Upgrade Addressable to version 2.9.1 or later. All earlier Addressable versions are affected.