February 26, 2025·4 min read·engineeringrubysecuritycgiuri

Ruby fixes repeated cookie copying and URI credential inheritance

February's CGI and URI advisories cover two CPU-exhaustion paths and credential leakage during URI composition. The fixes address different implementation boundaries and have distinct affected-version rules.

Combining two valid URI objects can still produce an unsafe result if credentials survive a change of destination. Ruby's February URI advisory describes precisely that failure. The URI library retained user information while replacing the host, so an application could construct a URL containing credentials intended for another destination.

The February 26 advisories also cover two CGI denial-of-service problems. One concerns super-linear cookie parsing. The other concerns a regular expression used while escaping selected HTML elements. These are distinct operations, despite appearing in the same gem and sharing corrected version lines.

I appreciate Ruby's readable interfaces, but a concise call can conceal substantial parsing and allocation work. These advisories illustrate why the implementation contract matters alongside the object model. A method's ordinary-looking input can influence either resource consumption or the security meaning of a composed value.

CVE-2025-27219 affects CGI::Cookie.parse. The advisory says a crafted cookie string could trigger super-linear parsing time. The 0.4.1 implementation shows how repeated names accumulated values before the fix.

For an already-seen name, the parser constructed a new array by adding the old values to the newly parsed values. It then created a replacement cookie object. Repeating the same name meant copying the growing accumulated prefix again. The work could increase faster than the input length because earlier values were repeatedly revisited.

The 0.4.2 implementation instead appends new values to the existing cookie with concat. The first occurrence still creates the cookie. Later occurrences update its value array without rebuilding the entire accumulated cookie at each step.

This is a useful example of an algorithmic resource problem without a complicated regex. An operation that is cheap for one pair can become expensive when a parser repeats it against growing state. The attacker influences the sequence of names, while the parser's accumulation strategy determines how much copying that sequence requires.

The advisory identifies affected CGI versions through 0.3.5, plus 0.3.6, 0.4.0, and 0.4.1. It names 0.3.5.1, 0.3.7, and 0.4.2 as corrected versions on their respective lines. The relevant component is the loaded CGI gem, so the interpreter's broad version family does not by itself describe which implementation the application uses.

Element escaping had a regex-specific problem

CVE-2025-27220 affects CGI::Util#escapeElement. This method escapes selected HTML elements in a string. The advisory identifies its regular expression as vulnerable to crafted input that consumes excessive CPU. It explicitly limits this vulnerability's Ruby-runtime impact to Ruby 3.1 and 3.2.

The fixed utility implementation matches selected element names and their contents with a revised pattern. Its treatment of characters inside an element avoids the vulnerable matching behavior while preserving the method's role of escaping the selected match.

This is different from the repeated-array problem in cookie parsing. Both can consume CPU, but they require different reasoning about the implementation. One follows the cost of copying accumulated values. The other follows how a regex handles a crafted string. Calling both cookie-parser bugs would misidentify the affected entry points.

The advisory gives the same corrected CGI gem versions for this issue. Its additional Ruby-version qualification remains relevant. A component can have a vulnerable-looking implementation version while a particular runtime's matching behavior changes whether the documented attack applies. The published scope should therefore be preserved instead of extending the claim to every Ruby interpreter.

Replacing an authority must replace its credentials

CVE-2025-27221 concerns user information retained by URI#join, URI#merge, and URI#+. The advisory describes user information such as user:password remaining after the host changes. Leakage can occur when the resulting URL points to a malicious host and someone accesses it.

The URI 1.0.3 implementation handles a replacement authority by setting user information from the new relative URI, alongside its host and port. It also defines + as an alias of merge. These relationships explain why one composition rule affects several public methods.

The same implementation handles an absolute incoming URI by returning that URI directly. The problematic inheritance belongs to combining a base with a reference. Reading the actual merge branches therefore gives more useful information than treating all URI construction as equivalent.

The security boundary concerns which authority a credential belongs to. A relative path on the existing destination can reasonably preserve the base authority. A reference supplying a different authority requires different treatment. Keeping the old user information while accepting the new host combines components whose relationship the caller did not intend.

The advisory does not claim that parsing a URL alone sends a secret over the network. It describes generating a URL and then having that URL accessed. Keeping those stages separate gives an application maintainer a more accurate account of where the unwanted credential becomes available and what subsequent action can expose it.

Corrected URI versions are 0.11.3, 0.12.4, 0.13.2, and 1.0.3. The affected lines have different upper bounds, as the advisory specifies. Updating URI and updating CGI are separate component changes even though Ruby published their disclosures together.

The interfaces retain their ordinary purpose

The fixes preserve cookie accumulation, selected-element escaping, and URI composition as useful operations. They change the internal handling of repeated input and replacement components. Applications do not need a new language construct to receive the corrected behavior.

I see these as concrete maintenance obligations for a language whose convenience methods do substantial work. The concise API is valuable when its implementation also respects resource and authority boundaries. The published advisories identify the methods and component versions that need correction, while the source changes explain why the ordinary operations required different handling.