CVE-2026-46727
Description
An issue was discovered in Ruby 4 before 4.0.5. A race condition leading to a use-after-free in the pthread-based getaddrinfo timeout handler (rb_getaddrinfo in ext/socket/raddrinfo.c) allows a remote attacker who can delay DNS responses near the user-specified timeout to crash a Ruby process that calls Addrinfo.getaddrinfo(..., timeout:) or Socket.tcp(..., resolv_timeout:). Memory-corruption-based exploitation is theoretically possible. The attack could, for example, be carried out through a crafted authoritative DNS server or recursive resolver.
Affected products
1Patches
16f1fa82e2eb3Fix reading freed memory in rb_getaddrinfo
1 file changed · +3 −7
ext/socket/raddrinfo.c+3 −7 modified@@ -601,13 +601,9 @@ rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hint if (need_free) free_getaddrinfo_arg(arg); if (timedout) { - if (arg->ai) { - rsock_raise_user_specified_timeout(arg->ai, Qnil, Qnil); - } else { - VALUE host = rb_str_new_cstr(hostp); - VALUE port = rb_str_new_cstr(portp); - rsock_raise_user_specified_timeout(NULL, host, port); - } + VALUE host = rb_str_new_cstr(hostp); + VALUE port = rb_str_new_cstr(portp); + rsock_raise_user_specified_timeout(NULL, host, port); } // If the current thread is interrupted by asynchronous exception, the following raises the exception.
Vulnerability mechanics
Root cause
"Use-after-free in rb_getaddrinfo caused by accessing arg->ai after the worker thread has freed it via free_getaddrinfo_arg."
Attack vector
A remote attacker who can control or influence DNS response timing (e.g., via a crafted authoritative DNS server or recursive resolver) triggers a race condition. The attacker delays DNS responses so they arrive just after the user-specified timeout expires. When `rb_getaddrinfo` processes the timeout, it frees the `addrinfo` argument and then reads the freed `arg->ai` pointer, causing a use-after-free. This can crash the Ruby process and may be exploitable for memory corruption.
Affected code
The vulnerability resides in `rb_getaddrinfo` in `ext/socket/raddrinfo.c`. When a user-specified timeout fires, the old code accessed `arg->ai` (the `addrinfo` result) after the worker thread had already freed it, because `free_getaddrinfo_arg(arg)` was called before the `timedout` branch. This creates a use-after-free on the `ai` pointer.
What the fix does
The patch removes the conditional branch that checked `arg->ai` and called `rsock_raise_user_specified_timeout(arg->ai, ...)` after `free_getaddrinfo_arg(arg)` had already freed the memory. Instead, it always passes `NULL` for the `ai` argument and constructs the host/port strings from the original parameters. This eliminates the use-after-free because the freed `arg->ai` pointer is never dereferenced.
Preconditions
- configThe Ruby process must call Addrinfo.getaddrinfo(..., timeout:) or Socket.tcp(..., resolv_timeout:) with a user-specified timeout.
- networkThe attacker must be able to delay DNS responses (e.g., via a crafted authoritative DNS server or recursive resolver) so they arrive after the timeout fires.
Generated on May 23, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
2News mentions
0No linked articles in our index yet.