Mar 2, 2026·5 min read·7 visits
GNU `telnetd` fails to scrub environment variables when spawning `/bin/login` as root. This allows attackers to inject `CREDENTIALS_DIRECTORY` (bypassing authentication in `util-linux` 2.40+) or `GCONV_PATH` (loading malicious shared objects via `glibc`). The vulnerability leads to immediate root compromise.
A critical privilege escalation vulnerability exists in GNU Inetutils `telnetd` versions through 2.7. The daemon fails to properly sanitize the environment before executing the login process, allowing attackers to inject dangerous environment variables. Because `telnetd` executes `/bin/login` as root without triggering the kernel's `AT_SECURE` protection, these variables are preserved. This allows local attackers—and potentially remote attackers depending on configuration—to gain root privileges by manipulating `systemd` credentials or `glibc` character set conversion paths.
CVE-2026-28372 identifies a flaw in the environment sanitization logic of the GNU Inetutils telnetd daemon. The vulnerability arises from the interaction between the telnet daemon, the login binary, and the Linux kernel's handling of privileged process execution. Specifically, telnetd accepts environment variables from the client via the Telnet protocol (RFC 1572) and passes them to the /bin/login process.
Under normal circumstances, when a process transitions from a lower privilege level to a higher one (e.g., executing a SETUID binary), the Linux kernel sets the AT_SECURE auxiliary vector. This signals the dynamic linker (ld.so) and the C library (glibc) to scrub sensitive environment variables such as LD_PRELOAD, GCONV_PATH, and GLIBC_TUNABLES. This mechanism is a primary defense against environment injection attacks.
However, telnetd runs as root and executes /bin/login also as root. Because the User ID (UID) does not change during this execve call, the kernel does not set AT_SECURE. Consequently, login starts with a user-controlled environment in a non-secure mode. It becomes the sole responsibility of telnetd to sanitize this environment. The failure to filter variables like CREDENTIALS_DIRECTORY or GCONV_PATH allows attackers to influence the execution flow of the privileged login process.
The root cause is a logic error in telnetd regarding the assumption of security boundaries. The daemon relied on a blacklist approach (or insufficient filtering) to remove dangerous variables. Blacklisting is historically fragile; as new features are added to downstream components (like systemd integration in login or new glibc features), the list of dangerous variables expands, rendering previous blacklists obsolete.
Specifically, the regression relates to CVE-1999-0073, a 27-year-old vulnerability involving telnetd and LD_ variables. While LD_PRELOAD might have been filtered in intervening years, newer variables like CREDENTIALS_DIRECTORY (introduced in util-linux 2.40) were not anticipated. The lack of AT_SECURE means that glibc honors these variables just as it would for a normal user process.
When telnetd constructs the argument vector for login, it copies environment variables provided by the client. Without a strict whitelist (e.g., only allowing TERM, DISPLAY, USER), any variable not explicitly blocked is passed through. This passes control of critical configuration paths—such as where to load shared libraries or where to read authentication credentials—directly to the attacker.
The first major exploitation vector targets the CREDENTIALS_DIRECTORY environment variable, supported by util-linux versions 2.40 and later. This variable is part of the systemd service credentials specification. When login initializes, it checks this directory for credential files.
If an attacker can define CREDENTIALS_DIRECTORY, they can point it to a directory they control, such as /tmp/fake_cred. The login process will search this directory for a file named login.noauth. If this file exists and contains the string "yes", login is instructed to bypass password authentication entirely.
To exploit this, a local user creates the directory and file, then connects to the local telnetd instance. By using the Telnet ENVIRON option to export CREDENTIALS_DIRECTORY=/tmp/fake_cred, the attacker forces the spawned login process to read their malicious configuration. This results in an immediate root shell without a password.
The second vector exploits the GCONV_PATH variable used by glibc for character set conversion. This is a classic attack method effectively reintroduced because AT_SECURE is missing. The iconv_open() function in glibc uses GCONV_PATH to locate shared objects (.so files) that handle specific character encodings.
An attacker creates a malicious shared object and a gconv-modules configuration file in a writable directory. They then connect via Telnet and export three variables: GCONV_PATH (pointing to their directory), LANGUAGE (setting a locale that requires conversion), and OUTPUT_CHARSET (specifying the target charset).
When /bin/login runs, it attempts to localize its output (e.g., printing the "Login:" prompt). This triggers gettext, which calls iconv_open to convert the message to the requested charset. glibc sees the attacker's GCONV_PATH, loads the malicious shared object to handle the conversion, and executes the attacker's code with root privileges. This execution happens before authentication is even attempted.
The impact of CVE-2026-28372 is critical, resulting in Local Privilege Escalation (LPE) to root. While the vulnerability manifests in the telnetd daemon, the successful exploitation relies on the configuration of the system (presence of util-linux >= 2.40 for Vector 1) or standard glibc behavior (Vector 2).
Confidentiality: Complete loss. An attacker can read any file on the system, including /etc/shadow and database credentials.
Integrity: Complete loss. An attacker can modify system binaries, install persistence mechanisms, or alter logs.
Availability: Complete loss. An attacker can delete files, stop services, or reboot the system.
The requirement for telnetd to be running reduces the attack surface on modern systems, where SSH is the standard. However, legacy systems, embedded devices, and specific enterprise environments running GNU Inetutils are highly vulnerable. The exploit is reliable and requires no race conditions or complex memory corruption.
The primary remediation is to apply the official patch which shifts telnetd from a blacklist approach to a whitelist approach. The patched version explicitly unsets all environment variables except for a small set of known-safe variables (like TERM).
Patched Versions: Users must upgrade to GNU inetutils version 2.8 or apply the patch found in commit 3953943d8296310485f98963883a798545ab9a6c.
Operational Workarounds:
telnetd service immediately. Replace it with OpenSSH, which has a robust history of secure environment handling.localhost or trusted management IPs to prevent remote triggering of the vulnerability, although this does not prevent local users from exploiting it via loopback.telnetd or login from reading files in /tmp or loading arbitrary shared objects, effectively neutralizing the exploit vectors.CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
inetutils GNU | <= 2.7 | 2.8 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-829 |
| Attack Vector | Local / Network (if allowed) |
| CVSS v3.1 | 7.4 (High) |
| EPSS Score | 0.01% (Low probability) |
| Impact | Privilege Escalation (Root) |
| Exploit Status | Proof of Concept Available |
Inclusion of Functionality from Untrusted Control Sphere