Overview
CVE-2026-32746 is a critical pre-authentication Remote Code Execution vulnerability in GNU inetutils telnetd, affecting all versions through 2.7. It carries a CVSS score of 9.8 and was discovered by the Dream Security Research Team, who reported it on March 11, 2026.
The vulnerability is a BSS-based buffer overflow in the LINEMODE SLC (Set Local Characters) suboption handler. An unauthenticated attacker can trigger it during the initial Telnet handshake, before any login prompt appears, with a single crafted TCP connection to port 23. No credentials, no user interaction, no special network position required.
What makes this one particularly notable is its age. The vulnerable code was introduced in 1994, making it a 32-year-old bug hiding in plain sight. An essentially identical flaw existed on the Telnet client side and was patched in 2005 (CVE-2005-0469), but nobody thought to check the server-side implementation for the same issue for another two decades.
Affected Versions & Scope
The primary affected package is GNU inetutils telnetd through version 2.7. However, because the same vulnerable BSD telnetd codebase has been widely copied and forked over the decades, the blast radius is significantly larger than just inetutils. Confirmed affected implementations include:
| Platform | Notes |
|---|---|
| inetutils-telnetd | All versions through 2.7, primary affected package |
| Debian / Ubuntu | Packages ship vulnerable inetutils |
| FreeBSD 13 / 15 | Forked from same BSD codebase |
| NetBSD 10.1 | Same codebase origin |
| Citrix NetScaler | Confirmed affected |
| Apple Mac Tahoe | Confirmed via source review |
| Haiku | Confirmed affected |
| TrueNAS Core | Confirmed affected |
| uCLinux | Confirmed affected |
| DragonFlyBSD | Confirmed affected |
Background: What is LINEMODE SLC?
To understand the vulnerability you need a basic grasp of how Telnet negotiation works.
Telnet isn’t just a raw TCP stream. It supports in-band feature negotiation via the IAC (Interpret As Command) byte, 0xFF, used to signal protocol control messages. One of the features that can be negotiated is LINEMODE, defined in RFC 1184. LINEMODE allows the Telnet client to perform local line editing rather than sending each keystroke individually, reducing network traffic.
Within LINEMODE, the SLC (Set Local Characters) suboption is used to negotiate special control characters. The server sends the client a list of three-byte triplets in the format [function, flag, value], describing what special characters (backspace, interrupt, etc.) map to which control codes. The client can then respond with its own triplets to override any of these values.
The negotiation flow looks like this:
Server: IAC DO LINEMODE (0xFF 0xFD 0x22)
Client: IAC WILL LINEMODE (0xFF 0xFB 0x22)
Client: IAC SB LINEMODE LM_SLC <triplets> IAC SE
The server receives the client’s SLC triplets and stores them in a global fixed-size buffer. Or rather, it’s supposed to. It doesn’t check whether that buffer is full before writing.
Root Cause
The vulnerability lives in telnetd/slc.c, specifically in the add_slc() function, which appends each received SLC triplet to the global slcbuf array:
// Vulnerable code in add_slc()
static void
add_slc(unsigned char func, unsigned char flag, cc_t val)
{
if ((*slcptr++ = (unsigned char) func) == 0xff)
*slcptr++ = 0xff;
if ((*slcptr++ = (unsigned char) flag) == 0xff)
*slcptr++ = 0xff;
if ((*slcptr++ = (unsigned char) val) == 0xff)
*slcptr++ = 0xff;
}
The slcbuf array is 108 bytes (0x6C) fixed in size. add_slc() writes 3 bytes per SLC triplet, expanding to up to 6 bytes if any byte equals 0xFF (which gets doubled as part of Telnet IAC escaping). There is no check that slcptr hasn’t gone past the end of slcbuf before writing.
An attacker can send 40+ SLC triplets during the handshake, overflowing the buffer and corrupting up to 400 bytes of adjacent BSS memory, including adjacent global variables and pointers.
The fix, applied in git commit 6864598, is a single bounds check:
// Patched add_slc()
static void
add_slc(unsigned char func, unsigned char flag, cc_t val)
{
// Ensure slcptr does not exceed slcbuf bounds
if ((slcptr - slcbuf) >= (sizeof(slcbuf) - 6))
return;
if ((*slcptr++ = (unsigned char) func) == 0xff)
*slcptr++ = 0xff;
if ((*slcptr++ = (unsigned char) flag) == 0xff)
*slcptr++ = 0xff;
if ((*slcptr++ = (unsigned char) val) == 0xff)
*slcptr++ = 0xff;
}
One bounds check. 32 years. The same fix that was applied to the client-side equivalent in 2005.
Exploitation Complexity
It’s worth being direct about this: reliable RCE is hard with this bug. The overflow is real and controllable, but converting it into code execution has several meaningful hurdles.
Triplet constraints. The data you can write is not arbitrary. The process_slc() function applies restrictions before calling add_slc(). If the func byte is greater than NSLC (0x1e), the rest of the triplet gets zeroed out. If func is zero, the triplet is discarded entirely. The flag byte has its bottom two bits manipulated, and 0xFF bytes get doubled (IAC escaping), which can expand triplets from 3 to up to 6 bytes.
BSS layout is compiler and build dependent. The global variables adjacent to slcbuf vary between builds, distributions, and architectures. What you can usefully overwrite on one binary may differ entirely on another. There is no universal gadget chain.
Packet size. The entire SLC subnegotiation must fit in a single Telnet packet of 0x200 bytes. Combined with the 0x6C buffer size, this limits the overflow window to roughly 0x190 bytes of adjacent memory.
Modern mitigations. ASLR, stack canaries, and NX all complicate turning a BSS overflow into reliable code execution on modern systems.
WatchTowr Labs, who published the most detailed public analysis, concluded that while memory corruption and pointer leaks are achievable, reliable RCE requires significant per-target tuning. That said, on legacy or embedded systems without modern mitigations (which are exactly the kind of systems still running Telnet), the picture is considerably bleaker.
PoC: Lab Setup & Demonstration
Disclaimer: The following is for authorised penetration testing and educational purposes only. Never run this against systems you do not own or have explicit written permission to test.
The public PoC by jeffaf on GitHub provides a fully isolated Docker lab and demonstrates the overflow via SLC response analysis. Note that this PoC triggers and verifies the buffer overflow but does not achieve full code execution, reliable RCE requires per-target tuning as described above.
Prerequisites
git clone https://github.com/jeffaf/cve-2026-32746
cd cve-2026-32746
docker compose up -d
This spins up a Debian container running inetutils-telnetd 2.4 under xinetd, exposed on port 2323. Nothing touches your host system.
Step 1: Detect (non-destructive)
Check whether the target is vulnerable by probing for LINEMODE support and observing the response:
python3 detect.py 127.0.0.1 2323
The detection script sends crafted SLC triplets that slightly exceed expected limits and inspects the server response. A vulnerable server echoes the overflow back, confirming the condition was accepted. A patched server discards the excess silently.
Step 2: Trigger the overflow
python3 exploit.py 127.0.0.1 2323
This sends a crafted SLC suboption during the Telnet handshake with 40+ triplets containing function codes greater than NSLC (18/0x12). The server writes them all into slcbuf without bounds checking, overflowing into adjacent BSS memory. The script then analyses the server’s SLC response to confirm leaked BSS data, proof that adjacent memory has been corrupted.
Step 3: Verify
# Confirm the overflow via server response analysis
# A successful run will show BSS data leaked in the SLC reply
# Cleanup
docker compose down
What the traffic looks like
# Client triggers LINEMODE negotiation
-> FF FB 22 (IAC WILL LINEMODE)
# Server acknowledges and sends SLC list
<- FF FA 03 ... (IAC SB LINEMODE SLC <normal triplets> IAC SE)
# Client sends malicious oversized SLC reply
-> FF FA 03 <40+ crafted triplets> FF F0
# Server processes without bounds checking
# slcbuf overflows into adjacent BSS variables
# Server SLC response leaks overwritten data
<- FF FA 03 <corrupted response containing BSS data> FF F0
Detection
Look for anomalous Telnet handshake traffic with oversized LINEMODE SLC subnegotiations. Specific indicators:
# Unusual SLC suboption packets: normal SLC lists are small
# Flag any IAC SB LINEMODE SLC sequences containing 40+ triplets
# Telnetd crashes or segfaults: a failed exploitation attempt
journalctl -u telnet.socket | grep -i "segfault\|crash\|killed"
dmesg | grep telnetd
# Unexpected processes spawned by telnetd
# On systems where exploitation succeeds
ps aux | grep -E "telnetd|inetd" --forest
# Syslog for xinetd/inetd connection anomalies
grep "telnet" /var/log/syslog | grep -v "connect"
Network-level detection, IDS/IPS signatures should flag:
# Telnet SLC subnegotiation with function codes > 0x1e
# IAC SB (0xFF 0xFA) followed by LINEMODE (0x22) with more than ~36 triplets
# Any Telnet SLC suboption packet approaching or exceeding 0x200 bytes
Remediation
The fix is a patched git commit, no official inetutils release yet. Version 2.7 remains vulnerable. Options in order of preference:
Option 1, Disable telnetd (strongly recommended)
If you don’t have a specific operational requirement for Telnet, disable it immediately:
# systemd
sudo systemctl stop telnet.socket
sudo systemctl disable telnet.socket
# xinetd: comment out or remove the telnet service block
sudo nano /etc/xinetd.d/telnet
# Set: disable = yes
sudo systemctl restart xinetd
# Verify nothing is listening on 23
ss -tlnp | grep :23
Option 2, Build from patched git commit
git clone https://git.savannah.gnu.org/git/inetutils.git
cd inetutils
# Checkout the patched commit or any commit after:
# 6864598a29b652a6b69a958f5cd1318aa2b258af
git checkout 6864598a29b652a6b69a958f5cd1318aa2b258af
./configure && make && sudo make install
Option 3, Block port 23 at the firewall (interim mitigation)
# iptables
sudo iptables -A INPUT -p tcp --dport 23 -j DROP
sudo iptables-save > /etc/iptables/rules.v4
# ufw
sudo ufw deny 23/tcp
# nftables
sudo nft add rule inet filter input tcp dport 23 drop
Option 4, Restrict to management networks only
If Telnet must remain operational for legacy or OT/ICS reasons, restrict access to trusted management networks only and ensure telnetd is not running as root where possible.
CVSS Breakdown
| Metric | Value |
|---|---|
| Base Score | 9.8 Critical |
| Attack Vector | Network |
| Attack Complexity | Low |
| Privileges Required | None |
| User Interaction | None |
| Scope | Unchanged |
| Confidentiality | High |
| Integrity | High |
| Availability | High |
Timeline
| Date | Event |
|---|---|
| 1994 | Vulnerable add_slc() code introduced in BSD telnetd |
| 2005 | Client-side equivalent (CVE-2005-0469) discovered and patched in slc_add_reply(), server side not reviewed |
| March 11, 2026 | Dream Security reports CVE-2026-32746 |
| March 13, 2026 | CVE published |
| March 19, 2026 | WatchTowr Labs publishes detailed technical analysis |
| March 2026 | Fix committed to inetutils git (6864598) |
| April 1, 2026 | Official patch deadline per Dream’s advisory |