What landed in CVE-land this week

This week's disclosure feed reads like a time capsule. Seven of the eight new entries touch ncurses, the terminal-handling library that ships with essentially every Unix-like operating system, and half are resurfaced research from 2017. One — CVE-2000-0963 — is old enough to vote. Age doesn't make them irrelevant. The real story isn't that ncurses has bugs; it's that ncurses has a bug class that keeps returning because the library sits under so much tooling that nobody remembers it's a parser.

If you run containers, CI runners, SSH bastions, or embedded Linux fleets, at least one thing in your environment links libncurses and reads TERM, TERMINFO, or TERMINFO_DIRS from an attacker-influenced environment. That's what this digest is about.

The digest at a glance

| CVE | Component | Class | Trigger | |---|---|---|---| | CVE-2000-0963 | ncurses | Buffer overflow | Long TERM / TERMINFO_DIRS env vars | | CVE-2002-0062 | ncurses 5.0 (RH ncurses4 compat) | Buffer overflow | Cursor-move / scroll routines | | CVE-2017-10684 | ncurses 6.0 | Stack overflow in fmt_entry | Crafted terminfo | | CVE-2017-10685 | ncurses 6.0 | Format string in fmt_entry | Crafted terminfo | | CVE-2017-11112 | ncurses 6.0 | OOB access in append_acs | Untrusted terminfo | | CVE-2017-11113 | ncurses 6.0 | NULL deref in _nc_parse_entry | Untrusted terminfo | | CVE-2017-13728 | ncurses 6.0 (libtic) | Infinite loop in next_char | Crafted input | | CVE-2017-13729 | ncurses 6.0 | Illegal address in _nc_save_str | Crafted input |

The CVSS column is missing on purpose. NVD is publishing these entries with 0.0 scores — the CNA has not yet assigned vectors — and that gap is exactly what an ops team will use to justify closing the ticket. Do not close the ticket. Severity here is contextual, and the context is where the work is.

Why terminfo is a parser you forgot you had

ncurses isn't just a "draw boxes on a TTY" library. It reads compiled terminfo entries from disk, walks each entry through _nc_read_entry / _nc_parse_entry / fmt_entry / _nc_save_str, and interprets embedded escape sequences and capability strings. Every 2017 CVE above is a bug in that parser. The attack surface is: any process that links ncurses and can be pointed at a terminfo entry the attacker controls.

The environment-variable path is the classic one. TERMINFO and TERMINFO_DIRS tell the library where to load from. If an attacker can influence those variables — a SUID binary with an unsanitized environment, a shared CI runner, a container that inherits the host's env, a su/sudo invocation with a permissive env_keep — the parser will consume a booby-trapped entry.

You can spot the risky call sites with a few commands. On a Debian/Ubuntu box:

# 1) Which binaries actually link ncurses?
find / -xdev -type f -perm -u+s -exec sh -c '
  ldd "$1" 2>/dev/null | grep -q "libncurses\|libtinfo" && printf "SUID+ncurses: %s\n" "$1"
' _ {} \;

# 2) Which processes are currently mapping libtinfo / libncurses?
lsof 2>/dev/null | awk '/libtinfo|libncurses/ {print $1, $2, $NF}' | sort -u

# 3) Are TERMINFO / TERMINFO_DIRS surviving privilege boundaries?
sudo -V | grep -Ei 'env_keep|env_reset'
grep -RIn 'TERMINFO' /etc/sudoers /etc/sudoers.d/ 2>/dev/null

If step 1 returns any SUID binary, you have a candidate for the CVE-2000-0963 / CVE-2002-0062 class regardless of the year on the CVE. If step 3 shows TERMINFO* in env_keep, that is the finding — you do not need a working PoC to file the ticket.

The 2017 cluster: crafted terminfo, not just long env vars

CVE-2017-10684 through CVE-2017-13729 are subtler. They don't require an env var; they require the parser to read a malicious compiled terminfo entry. That happens whenever an ncurses-linked program is asked to describe an unknown terminal, or whenever tic/infocmp is pointed at attacker-controlled data.

This goes wrong in predictable places:

The DoS-only entries (CVE-2017-11112, CVE-2017-11113, CVE-2017-13728, CVE-2017-13729) are the ones defenders underweight. On a build farm or a bastion, a parser that infinite-loops or dereferences NULL on demand gives a low-privileged tenant a cheap way to knock over a shared service. "Only a DoS" stops meaning "only a DoS" the moment the affected process is a health checker whose absence triggers an auto-heal that reboots a node an attacker is about to log into.

What to actually do this week

  1. Inventory ncurses. Every host, every container image, every appliance. dpkg -l | grep -E 'ncurses|tinfo' and rpm -qa | grep -E 'ncurses|tinfo' cover 90% of the fleet. Feed the versions into your SBOM diff.
  2. Confirm fix pedigree. Upstream fixes landed in ncurses 6.0-20170729; distros followed with their own patch series. If your image predates that with no vendor backport, patch or rebuild.
  3. **Strip TERMINFO* at privilege boundaries.** sudoers should have env_reset enabled and neither TERMINFO nor TERMINFO_DIRS in env_keep. su - is not automatic protection — audit the PAM stack.
  4. Constrain ~/.terminfo on multi-tenant hosts. If root-owned services parse user-writable terminfo entries, drop privileges before the parse or point the tool at a hardened TERMINFO prefix locked with chattr +i.
  5. Fuzz the boundary you own. If you ship a CLI or TUI that ingests external data and passes it to ncurses, add an AFL++/libFuzzer harness against setupterm() and tigetstr(). The 2017 crashes reproduce cheaply; regressions will too.

Old CVEs aren't "resolved" — they're dormant. The parser under your terminal deserves the same scrutiny you give your JSON, YAML, and XML paths. Teams that use legacy library CVEs to trace where their tooling reads untrusted bytes ship fewer incidents than teams that grade risk by CVSS and stop reading at 0.0.

Patch the images, strip the env, fuzz the seam.

Verifiable security.