On Tue, Feb 24, 2026 at 06:29:43AM +0100, Solar Designer wrote:
> On Tue, Feb 24, 2026 at 03:17:02AM +0200, Justin Swartz wrote:
> > In my opinion, to fix this issue and finally put the ghost of CVE-1999-0073
> > to rest: telnetd must drop the blacklist approach and adopt the OpenSSH
> > AcceptEnv-style approach suggested by Simon Josefsson [1], which amounts to
> > preparing a brand new environment for /bin/login based on a strict
> > whitelist of variables names considered to be "safe", and perhaps a healthy
> > dose of input sanitization for their respective values.
>
> Oh, sure. A couple of decades ago I ported OpenBSD's telnet and telnetd
> to Linux for our distro, Owl. I no longer recalled all detail, but
> looking at my "Linux port" patch now, it appears to implement a strict
> allow-list approach already. There's a comment saying the "list comes
> from Linux NetKit telnetd, version 0.17", so maybe NetKit already used
> that approach too, and Linux distros got a regression by switching from
> NetKit to InetUtils? Or it could be that Red Hat used NetKit and Debian
> went with InetUtils. I see I'm also lightly sanitizing env var values
> (only for not containing '/' and being of sane length), which I doubt
> was in NetKit.
I'm now looking at telnet-0.17-85.el9.src.rpm from Rocky Linux 9. The
telnet server part of it is still based on NetKit 0.17, where the latest
ChangeLog entry is:
22-Jul-2000:
Bug fixes for environment processing from Olaf Kirch. Also fixes
privacy issue noticed by Steve Bellovin. Also fix a wrong
assert().
and the code is:
/* check that variable is safe to pass to login or shell */
#if 0 /* insecure version */
static int envvarok(char *varp) {
if (strncmp(varp, "LD_", strlen("LD_")) &&
strncmp(varp, "ELF_LD_", strlen("ELF_LD_")) &&
strncmp(varp, "AOUT_LD_", strlen("AOUT_LD_")) &&
strncmp(varp, "_RLD_", strlen("_RLD_")) &&
strcmp(varp, "LIBPATH") &&
strcmp(varp, "ENV") &&
strcmp(varp, "IFS"))
{
return 1;
}
else {
/* optionally syslog(LOG_INFO) here */
return 0;
}
}
#else
static int envvarok(char *varp) {
/*
* Allow only these variables.
*/
if (!strcmp(varp, "TERM")) return 1;
if (!strcmp(varp, "DISPLAY")) return 1;
if (!strcmp(varp, "USER")) return 1;
if (!strcmp(varp, "LOGNAME")) return 1;
if (!strcmp(varp, "POSIXLY_CORRECT")) return 1;
/* optionally syslog(LOG_INFO) here */
return 0;
}
In my patch against OpenBSD's it is:
+/* This list comes from Linux NetKit telnetd, version 0.17 */
+static char *goodenv_table[] = {
+ "TERM",
+ "DISPLAY",
+ "USER",
+ "LOGNAME",
+ "POSIXLY_CORRECT",
+ NULL
};
[...]
+envvarok(varp, valp)
+ char *varp, *valp;
{
[...]
+ for (i = 0; goodenv_table[i]; i++) {
+ if (strcmp(goodenv_table[i], varp))
+ continue;
+ if (strchr(valp, '/') || strlen(valp) >= 0x100) {
+ syslog(LOG_NOTICE, "Rejected attempt to set the "
+ "environment variable \"%s\" to an "
+ "invalid value", varp);
+ return (0);
+ }
+ return (1);
+ }
[...]
+ return (0);
So it looks like in the Linux world non-use of an allow list is specific
to InetUtils, which means primarily Debian and derived distros.
Alexander