August 27, 2026·5 min read·engineeringrubysecuritydns

Ruby resolv fixes DNS memory growth and hostname disagreement

Two resolv vulnerabilities affect applications using Ruby's DNS implementation. One retains attacker-controlled response data, while another lets an overlong name resolve differently from the validated string.

An application can approve a hostname and still connect somewhere it did not intend if its validator and resolver interpret the string differently. Ruby's August 27 resolv advisories describe that failure alongside a separate memory-exhaustion vulnerability. Both affect the Ruby resolv gem. Ordinary socket name resolution through the operating system is outside the disclosed scope.

The distinction between resolver implementations is central to this event. The advisory explicitly says Net::HTTP loads resolv for IP address regular expressions but normally resolves through the operating system. Seeing the gem in a process therefore does not establish exposure. The relevant question is whether a lookup actually reaches the gem's resolution code.

I appreciate Ruby's consistent object model, but that consistency can make alternative implementations look more interchangeable than they are. A dependency can expose a familiar networking operation while routing it through different code. These advisories reward knowing which implementation owns the lookup, because that fact determines both the affected behavior and the package that needs correction.

The two failures have different attacker inputs

CVE-2026-80212 concerns responses from an attacker-controlled name server. An application resolving an influenced hostname, such as a webhook destination or user-provided URL, can retain response data permanently. Repeating the lookups grows the process's memory until it runs out and stops providing service. The advisory describes unbounded retention, without attributing the problem to the operating system's resolver.

That makes repeated activity part of the disclosed failure. The response does not merely cause one unusually large allocation that disappears after a request. Retaining data across lookups lets the process accumulate the cost. The lifecycle of the retained objects matters as much as the size of any individual response.

CVE-2026-80213 instead concerns an overlong hostname. A string can pass an application's allow list or SSRF check and then become a different name when resolved. Authorization applies to one representation, while the actual network lookup uses another. The advisory says the defect requires names exceeding DNS length limits.

These vulnerabilities should not be combined into a single generic warning about malicious DNS. One consumes resources through retained response data. The other defeats a hostname-based policy through disagreement about the input's meaning. They share a library, but their prerequisites and consequences differ.

Length limits belong in the name representation

The advisory identifies two limits relevant to the validation bypass, a complete DNS name no longer than 255 octets and individual labels no longer than 63 octets. Validation already rejecting names beyond those limits avoids the disclosed bypass. The units are octets, so a character-count check is not an interchangeable description of the stated condition.

The 0.7.2 source enforces label size when constructing Label::Str. It measures the string's byte size and rejects labels exceeding the limit. Placing the restriction in the label object makes it an invariant of that representation, including labels created through different callers. The code no longer relies solely on an application having performed the right preliminary check.

For a name created from a string, the implementation also counts the encoded total. It starts with the root label's terminating zero octet and adds a length octet plus the byte size of every label. That total is checked against 255. This is more precise than treating the visible dotted string's character length as the entire wire representation.

The input conversion translates an invalid label-size error into ResolvError, consistent with other name-resolution failures. Passing the wrong kind of object remains an ArgumentError. The distinction gives callers a meaningful way to separate invalid runtime hostname data from an API usage error.

Response decoding needs corresponding restrictions

The corrected decoder performs size checks while reading a DNS name from a response. Its label reader rejects oversized labels through the same representation and converts that failure into a decoding error. The source comments call out length-byte values previously treated as label lengths even though the protocol reserves them.

The name decoder also follows compression pointers under explicit restrictions and counts the expanded label data. It rejects non-backward pointers and names exceeding the total limit. These checks concern the received representation, where a compact wire encoding still needs to produce a valid name. Restrictions at string construction alone would not describe every path by which the library obtains labels.

This illustrates a practical design benefit of a shared constrained type. Input conversion and response decoding can use the same label invariant while reporting errors appropriate to their respective APIs. The resulting code has fewer places where a label's size is merely an assumption. That is directly relevant to the disagreement between validated input and network behavior.

Exposure depends on how the application resolves

The advisory identifies direct use of Resolv, dependencies that perform those lookups, and resolv-replace as ways to reach affected code. Loading resolv-replace routes socket name resolution through the gem. This can make a socket-based application relevant even when its own source never calls Resolv.getaddress explicitly.

Conversely, Net::HTTP's use of the gem's regular expressions does not make its ordinary connections vulnerable through this path. A dependency inventory needs the call relationship, not merely a list of loaded files. The advisory is unusually helpful here because it names both the affected routes and a common false positive.

The recommended correction is resolv 0.7.2. Ruby 3.3 applications have the compatible patched 0.3.2 line. For Ruby 3.2, the advisory says no 0.2.x release is planned because that interpreter series has reached end of life, and recommends installing 0.7.2 instead. The package's own selected version is the remediation target.

The published affected ranges include 0.4.0 through 0.7.1 and 0.3.1 and earlier. That span crosses different Ruby interpreter series, which is why an interpreter version alone cannot settle the question. The running application's resolver choice and loaded gem version together determine whether the fix has reached the code that handles its DNS traffic.

My qualified affection for Ruby includes its ability to express useful behavior through small libraries. Here that flexibility makes the implementation boundary worth stating explicitly. Updating resolv repairs the disclosed paths, while maintaining a hostname policy still requires the approved representation to agree with the one used for the network operation. The corrected library's byte-based label and name limits supply part of that agreement.