#!/usr/bin/env bash # cve-2026-98432-check.sh - checks a Linux host for the TCP use-after-free CVE-2026-98432 # https://nokkela.blog/en/content/linux-kernel-tcp-cve-2026-98432.html # # SPDX-License-Identifier: BSD-2-Clause # Copyright (c) 2026 Nokkela-IT-Concept GmbH # Status and spinner functions from lxc-to-go, Copyright (c) Daniel Plominski (BSD-2-Clause). # # Redistribution and use in source and binary forms, with or without modification, are permitted # provided that the following conditions are met: # 1. Redistributions of source code must retain the above copyright notice, this list of # conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright notice, this list of # conditions and the following disclaimer in the documentation and/or other materials provided # with the distribution. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND # FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # Read-only check for Debian, Ubuntu and Proxmox VE hosts: is the running kernel fixed, is a fixed # kernel installed, and which settings widen the exposure until it is. Nothing on the system is # changed; the only file written is the report. # # The console shows fixed texts, kernel versions and counts only, so a whole run (command line # and output) can go into a chat as it is. Listening addresses, ports and processes go to the # report under /opt/cve-2026-98432-check/reports (directory 0700, report 0600). # # sudo bash cve-2026-98432-check.sh # # The flaw (2026-10-15): tcp_v4_syn_recv_sock() hands the IPv4 options of a connection request to # the child socket without copying them; a retransmitted SYN can make the SYN-ACK path read them # after they were freed. Present since Linux 4.4, fixed upstream by e3f33b0a1d89 (7.3-rc7). # Native IPv6 is not affected; IPv4 connections to dual-stack sockets are. # # Fixed versions as of 2026-10-31: kernel CNA announcement (stable branches), Debian DSA-6568-1 # (2026-10-16), DLA-4841-1 (2026-10-17), DLA-4850-1 (2026-10-22), Proxmox pve-kernel 7.0.14-25 # (2026-10-17), Ubuntu CVE tracker of 2026-10-30 (fixes pending, none released yet; the fixed # generic kernels sit in -proposed). Older Ubuntu kernels are no way out: every kernel # below the fixed version carries the flaw. set -u umask 077 export LC_ALL=C SCRIPT_VERSION=1.0.1 REPORT_DIR=/opt/cve-2026-98432-check/reports AS_OF=2026-10-31 # First fixed release per upstream stable series; every series from 7.3 on contains the fix declare -A UPSTREAM_FIX=([5.10]=5.10.272 [5.15]=5.15.223 [6.1]=6.1.190 [6.6]=6.6.159 [6.12]=6.12.113 [6.18]=6.18.56 [7.2]=7.2.10) # Debian package versions (linux, linux-6.12; DSA-6568-1, DLA-4841-1, DLA-4850-1, unstable). # 6.12.113-1~deb12u1 sorts below 6.12.113-1 and so covers trixie and bookworm alike. declare -A DEBIAN_FIX=([6.1]=6.1.190-1 [6.12]=6.12.113-1~deb12u1 [7.2]=7.2.10-1) # Proxmox VE kernel with the fix (proxmox-kernel-7.0, sources Ubuntu-7.0.0-43.43i1) PVE_FIX=7.0.14-25 # Ubuntu source package and series -> version announced with the fix (CVE tracker, status # pending, 2026-10-30 19:44 UTC). "announced" means pending without a version yet. declare -A UBUNTU_FIX=( [linux:7.3]=7.3.0-10.10 [linux:7.0]=7.0.0-43.43 [linux:6.8]=6.8.0-149.149 [linux:5.15]=5.15.0-203.213 [linux-hwe-6.8:6.8]=6.8.0-149.149~22.04.1 [linux-lowlatency:6.8]=6.8.0-149.149.1 [linux-lowlatency:5.15]=5.15.0-198.208 [linux-lowlatency-hwe-6.8:6.8]=6.8.0-149.149.1~22.04.1 [linux-lowlatency-hwe-5.15:5.15]=5.15.0-198.208~20.04.1 [linux-aws:7.3]=7.3.0-1004.4 [linux-aws:7.0]=7.0.0-1017.18 [linux-aws:6.8]=6.8.0-1069.74 [linux-aws:5.15]=5.15.0-1120.127 [linux-aws-7.0:7.0]=7.0.0-1017.18~24.04.1 [linux-aws-6.8:6.8]=6.8.0-1069.74~22.04.1 [linux-aws-5.15:5.15]=5.15.0-1120.127~20.04.1 [linux-azure:7.3]=7.3.0-1004.4 [linux-azure:7.0]=7.0.0-1020.21 [linux-azure:6.8]=6.8.0-1073.82 [linux-azure:5.15]=5.15.0-1126.135 [linux-azure-7.0:7.0]=7.0.0-1020.21~24.04.1 [linux-azure-6.8:6.8]=6.8.0-1073.82~22.04.1 [linux-azure-5.15:5.15]=5.15.0-1126.135~20.04.1 [linux-azure-fde:7.3]=7.3.0-1004.5 [linux-azure-fde:7.0]=7.0.0-1019.19 [linux-azure-fde:6.8]=6.8.0-1071.78 [linux-gcp:7.3]=7.3.0-1004.4 [linux-gcp:7.0]=7.0.0-1017.19 [linux-gcp:6.8]=6.8.0-1073.81 [linux-gcp:5.15]=5.15.0-1121.131 [linux-gcp-7.0:7.0]=7.0.0-1017.19~24.04.1 [linux-gcp-6.8:6.8]=6.8.0-1073.81~22.04.1 [linux-gcp-5.15:5.15]=5.15.0-1121.131~20.04.1 [linux-gke:7.0]=7.0.0-1010.11 [linux-gke:6.8]=6.8.0-1068.77 [linux-gke:5.15]=5.15.0-1116.122 [linux-gkeop:6.8]=6.8.0-1053.57 [linux-gkeop:5.15]=5.15.0-1103.111 [linux-oracle:7.3]=7.3.0-1004.4 [linux-oracle:7.0]=7.0.0-1016.18 [linux-oracle:6.8]=6.8.0-1067.71 [linux-oracle:5.15]=5.15.0-1117.123 [linux-oracle-7.0:7.0]=7.0.0-1016.18~24.04.1 [linux-oracle-5.15:5.15]=5.15.0-1117.123~20.04.1 [linux-ibm:7.0]=7.0.0-1018.18 [linux-ibm:6.8]=6.8.0-1069.70 [linux-ibm:5.15]=5.15.0-1114.118 [linux-ibm-5.15:5.15]=5.15.0-1114.118~20.04.1 [linux-kvm:5.15]=5.15.0-1112.117 [linux-nvidia:5.15]=5.15.0-1115.116 [linux-oem-7.0:7.0]=7.0.0-1018.18 [linux-raspi:7.3]=7.3.0-1004.4 [linux-xilinx:6.8]=6.8.0-1042.43 [linux-realtime:7.3]=7.3.0-10.10.1 [linux-realtime:6.8]=6.8.1-1064.65 [linux-realtime:5.15]=5.15.0-1119.128 [linux-intel-iotg:5.15]=5.15.0-1115.121 [linux-intel-iotg-5.15:5.15]=5.15.0-1115.121~20.04.1 [linux-fips:6.8]=6.8.0-149.149+fips2 [linux-fips:5.15]=5.15.0-203.213+fips1 [linux-aws-fips:6.8]=6.8.0-1069.74+fips1 [linux-aws-fips:5.15]=5.15.0-1120.127+fips1 [linux-azure-fips:6.8]=6.8.0-1073.82+fips1 [linux-azure-fips:5.15]=5.15.0-1126.135+fips1 [linux-gcp-fips:5.15]=5.15.0-1121.131+fips1 ) #// FUNCTION: status lines in the lxc-to-go format (Daniel Plominski, BSD-2-Clause) _ok() { printf '[\033[1;32m OK \033[0m] %s\n' "'$*'"; } _failed() { printf '[\033[1;31mFAILED\033[0m] %s\n' "'$*'"; } _soft() { printf '[\033[1;33mFAILED\033[0m] %s\n' "'$*'"; } info() { printf '[\033[1;36m INFO \033[0m] %s\n' "$*"; } header() { printf '\n\033[1;35m### %s\033[0m\n' "$*"; } #// FUNCTION: spinner (lxc-to-go 1.0, plus exit code of the job); draws on /dev/tty only spinner() { local pid=$1 spinstr='|/-\' temp out=/dev/null if { true >/dev/tty; } 2>/dev/null; then out=/dev/tty; fi while kill -0 "$pid" 2>/dev/null; do temp=${spinstr#?} printf ' [%c] ' "$spinstr" >"$out" spinstr=$temp${spinstr%"$temp"} sleep 0.1 printf '\b\b\b\b\b\b' >"$out" done printf ' \b\b\b\b\b\b' >"$out" wait "$pid" } RED=0 YELLOW=0 FIRST_LINE= #// FUNCTION: write a block to the report, print "report line(s) a-b" for the console # Runs in a command substitution, so the caller keeps FIRST_LINE up to date (mark_first). to_report() { local title=$1 file=$2 from to from=$(($(wc -l <"$REPORT") + 3)) { printf '\n## %s\n' "$title"; grep . "$file"; } >>"$REPORT" to=$(wc -l <"$REPORT") if [ "$from" -eq "$to" ]; then echo "report line $from"; else echo "report lines $from-$to"; fi } #// FUNCTION: remember where the first block will start, before to_report writes it mark_first() { [ -n "$FIRST_LINE" ] || FIRST_LINE=$(($(wc -l <"$REPORT") + 2)) } #// FUNCTION: run one check with spinner; each output line is a finding and goes to the report # run_check run_check() { local level=$1 clean=$2 found=$3 fn=$4 out n where out=$TMPD/$fn ("$fn" >"$out" 2>/dev/null) & spinner $! n=$(grep -c . "$out") if [ "$n" -eq 0 ]; then if [ "$level" = info ]; then info "$clean"; else _ok "$clean"; fi return 0 fi found=${found//@N@/$n} mark_first where=$(to_report "$found" "$out") case $level in soft) YELLOW=$((YELLOW + 1)); _soft "$found ($where)" ;; *) info "$found ($where)" ;; esac } #// FUNCTION: dpkg version comparison, true when $1 >= $2 ver_ge() { dpkg --compare-versions "$1" ge "$2" } #// FUNCTION: upstream part of a version (6.12.113-1~deb12u1 -> 6.12.113) upstream_of() { local v=${1%%[-+~]*} echo "${v%%[!0-9.]*}" } #// FUNCTION: series of a version (6.12.113-1 -> 6.12) series_of() { upstream_of "$1" | cut -d. -f1,2 } #// FUNCTION: verdict against the upstream stable series, "state|fixed version" upstream_verdict() { local up s fix up=$(upstream_of "$1") s=$(series_of "$1") if ! ver_ge "$up" 4.4; then echo "unaffected|"; return; fi if ver_ge "$up" 7.3~; then echo "fixed|7.3"; return; fi fix=${UPSTREAM_FIX[$s]:-} if [ -z "$fix" ]; then echo "nofix|"; return; fi if ver_ge "$up" "$fix"; then echo "fixed|$fix"; else echo "vuln|$fix"; fi } #// FUNCTION: verdict for one kernel, "state|fixed version"; states: fixed vuln nofix announced #// unaffected. kernel_verdict [ubuntu source:series] kernel_verdict() { local kind=$1 ver=$2 key=${3:-} fix s case $kind in proxmox) if ver_ge "$ver" "$PVE_FIX"; then echo "fixed|$PVE_FIX" elif ver_ge "$ver" 7.0~; then echo "vuln|$PVE_FIX" else echo "nofix|$PVE_FIX"; fi ;; ubuntu) fix=${UBUNTU_FIX[$key]:-} case $fix in '') echo "nofix|" ;; announced) echo "announced|" ;; *) if ver_ge "$ver" "$fix"; then echo "fixed|$fix"; else echo "vuln|$fix"; fi ;; esac ;; debian) s=$(series_of "$ver") fix=${DEBIAN_FIX[$s]:-} if [ -n "$fix" ]; then if ver_ge "$ver" "$fix"; then echo "fixed|$fix"; else echo "vuln|$fix"; fi else upstream_verdict "$ver" fi ;; *) upstream_verdict "$ver" ;; esac } #// FUNCTION: Ubuntu source package and series of a kernel, "source:series" # ubuntu_key , e.g. 6.8.0-149.149~22.04.1 generic -> linux-hwe-6.8:6.8 ubuntu_key() { local ver=$1 flav=$2 s src s=$(series_of "$ver") case $flav in generic | generic-64k | generic-lpae) flav= ;; lowlatency | lowlatency-64k) flav=lowlatency ;; esac if [[ $ver == *~[0-9][0-9].[0-9][0-9]* ]]; then case $flav in '') src=linux-hwe-$s ;; lowlatency) src=linux-lowlatency-hwe-$s ;; *) src=linux-$flav-$s ;; esac else case $flav in '') src=linux ;; oem) src=linux-oem-$s ;; *) src=linux-$flav ;; esac fi echo "$src:$s" } #// FUNCTION: identify the running kernel; sets K_KIND, K_VER, K_KEY # detect_kernel detect_kernel() { local rel=$1 ver=$2 sig=$3 abi flav K_KEY= if [[ $rel == *-pve ]]; then K_KIND=proxmox K_VER=${rel%-pve} elif [[ $sig == "Ubuntu "* ]]; then K_KIND=ubuntu abi=${sig#Ubuntu } abi=${abi%% *} flav=${rel#*-*-} K_VER=${abi%-"$flav"} K_KEY=$(ubuntu_key "$K_VER" "$flav") elif [[ $ver =~ Debian\ ([0-9][^ ]*) ]]; then K_KIND=debian K_VER=${BASH_REMATCH[1]} else K_KIND=other K_VER=$rel fi } #// FUNCTION: installed kernel packages as "package|version|kind|key", kind/key as detect_kernel installed_kernels() { local st pkg ver flav dpkg-query -W -f='${db:Status-Abbrev}|${Package}|${Version}\n' 2>/dev/null | while IFS='|' read -r st pkg ver; do [[ $st == ii* ]] || continue case $pkg in proxmox-kernel-[0-9]*-pve | proxmox-kernel-[0-9]*-pve-signed | \ pve-kernel-[0-9]*-pve | pve-kernel-[0-9]*-pve-signed) echo "$pkg|$ver|proxmox|" ;; linux-image-[0-9]*-dbg | linux-image-[0-9]*-dbgsym) ;; linux-image-[0-9]* | linux-image-unsigned-[0-9]*) # leftover Debian kernels on a Proxmox host are not what it boots if [ "$K_KIND" = proxmox ]; then continue elif [ "$K_KIND" = ubuntu ]; then flav=${pkg#linux-image-} flav=${flav#unsigned-} flav=${flav#*-*-} echo "$pkg|$ver|ubuntu|$(ubuntu_key "$ver" "$flav")" else echo "$pkg|$ver|debian|" fi ;; esac done } #// FUNCTION: sentence for a kernel that is not fixed not_fixed_text() { local state=$1 fix=$2 case $K_KIND:$state in proxmox:nofix) echo "Proxmox ships no fixed kernel for this series, $PVE_FIX-pve or newer is needed" ;; proxmox:*) echo "below the fixed Proxmox kernel $PVE_FIX-pve" ;; ubuntu:vuln) echo "below the fixed version $fix announced by Ubuntu" ;; ubuntu:announced) echo "Ubuntu has announced a fix for ${K_KEY%%:*}, but no version yet" ;; ubuntu:nofix) echo "Ubuntu has announced no fix for ${K_KEY%%:*} (as of $AS_OF)" ;; *:vuln) echo "below the fixed version $fix" ;; *) echo "no fixed version known for this kernel series" ;; esac } #// FUNCTION: container technology when this runs inside a container, empty otherwise in_container() { local v v=$(systemd-detect-virt -c 2>/dev/null) && [ "$v" != none ] && { echo "$v"; return; } [ -e /.dockerenv ] && { echo docker; return; } [ -e /run/.containerenv ] && { echo podman; return; } v=$(tr '\0' '\n' /dev/null | sed -n 's/^container=//p') [ -n "$v" ] && echo "$v" } #// CHECK: TCP listeners beyond loopback (IPv4 reaches dual-stack sockets as well) chk_listeners() { ss -H -ltnp 2>/dev/null | awk '$4 !~ /^(127\.|\[::1\]|\[::ffff:127\.)/ {p=$6; sub(/^users:/, "", p); print $4, p}' | sort -u } #// CHECK: MPTCP listeners (the path of the published exploit) chk_mptcp() { ss -H -Mltnp 2>/dev/null | awk '{p=$6; sub(/^users:/, "", p); print $4, p}' | sort -u } #// CHECK: request socket migration switched on (second path of the same race) chk_migrate() { local v v=$(sysctl -n net.ipv4.tcp_migrate_req 2>/dev/null) [ "$v" = 1 ] && echo "net.ipv4.tcp_migrate_req = 1" } #// CHECK: nftables rules that drop IPv4 packets carrying options (stopgap) chk_stopgap() { command -v nft >/dev/null || return 0 nft list ruleset 2>/dev/null | grep -E 'ip hdrlength (gt|>|!=) 5.*drop' | sed 's/^[[:space:]]*//' } usage() { cat <&2; exit 1 ;; esac if [ "$(id -u)" != 0 ]; then echo "[ERROR] This script must run as root (sudo)" 1>&2 exit 1 fi if ! command -v dpkg >/dev/null; then echo "[ERROR] This script supports Debian, Ubuntu and Proxmox VE (dpkg) only" 1>&2 exit 1 fi install -d -m 0700 "$REPORT_DIR" || exit 1 REPORT=$REPORT_DIR/report-$(date +%Y%m%d-%H%M%S).txt TMPD=$(mktemp -d) || exit 1 trap 'rm -rf "$TMPD"' EXIT # shellcheck disable=SC1091 . /etc/os-release 2>/dev/null detect_kernel "$(uname -r)" "$(uname -v)" "$(cat /proc/version_signature 2>/dev/null)" ctr=$(in_container) pve_major= command -v pveversion >/dev/null && pve_major=$(pveversion 2>/dev/null | sed -n 's|^pve-manager/\([0-9]*\).*|\1|p') { echo "cve-2026-98432-check $SCRIPT_VERSION (fixed versions as of $AS_OF)" echo "Host: $(hostname)" echo "Run: $(date '+%Y-%m-%d %H:%M:%S %z')" echo "System: ${PRETTY_NAME:-unknown}${pve_major:+, Proxmox VE $pve_major}${ctr:+, container ($ctr)}" echo "Kernel: $(uname -r) | $(uname -v)" echo "Detected: $K_KIND $K_VER${K_KEY:+ ($K_KEY)}" } >"$REPORT" header "cve-2026-98432-check $SCRIPT_VERSION (Linux TCP use-after-free), fixed versions as of $AS_OF" info "Platform ${PRETTY_NAME:-unknown}${pve_major:+, Proxmox VE $pve_major}" info "Running kernel $(uname -r) ($K_KIND${K_KEY:+, ${K_KEY%%:*}})" [ -z "$ctr" ] || info "Inside a container ($ctr): this kernel belongs to the host, fix it there" header "Kernel" IFS='|' read -r state fix <<<"$(kernel_verdict "$K_KIND" "$K_VER" "$K_KEY")" case $state in fixed) _ok "Running kernel $K_VER contains the fix ($fix or newer)" ;; unaffected) _ok "Running kernel $K_VER predates the flaw (Linux 4.4)" ;; *) text=$(not_fixed_text "$state" "$fix") if [ "$K_KIND" = other ]; then YELLOW=$((YELLOW + 1)) _soft "Kernel of unknown origin $K_VER: $text upstream, ask its vendor" else RED=$((RED + 1)) _failed "Running kernel $K_VER: $text" fi ;; esac [ "$K_KIND" = ubuntu ] && [ "$state" != fixed ] && info "Ubuntu had released no fixed kernel by $AS_OF; an older kernel is no way out." \ "Stopgaps and the -proposed kernel: see the article" [ "$pve_major" = 8 ] && info "Proxmox VE 8 is end of life (2026-08) and gets no fixed kernel: upgrade to Proxmox VE 9" command -v canonical-livepatch >/dev/null && info "Livepatch client present: this check judges the kernel version only" if [ -z "$ctr" ]; then installed_kernels >"$TMPD/installed" n_all=0 n_fixed=0 : >"$TMPD/installed-verdicts" while IFS='|' read -r pkg ver kind key; do n_all=$((n_all + 1)) IFS='|' read -r v _ <<<"$(kernel_verdict "$kind" "$ver" "$key")" [ "$v" = fixed ] && n_fixed=$((n_fixed + 1)) echo "$v $pkg $ver" >>"$TMPD/installed-verdicts" done <"$TMPD/installed" if [ "$n_all" -gt 0 ]; then text="Installed kernel packages: $n_all, with the fix: $n_fixed" mark_first text="$text ($(to_report "$text" "$TMPD/installed-verdicts"))" if [ "$n_fixed" -gt 0 ]; then _ok "$text" [ "$state" = fixed ] || [ "$state" = unaffected ] || info "A fixed kernel is installed but not running: reboot into it" elif [ "$state" = fixed ] || [ "$state" = unaffected ]; then info "$text" else _failed "$text: install the update (apt update && apt full-upgrade), then reboot" fi fi if command -v proxmox-boot-tool >/dev/null; then pin=$(proxmox-boot-tool kernel list 2>/dev/null | awk '/^Pinned kernel:/ {f=1; next} f && NF {print $1; exit}') if [ -n "$pin" ] && [[ $pin == *-pve ]]; then IFS='|' read -r v _ <<<"$(kernel_verdict proxmox "${pin%-pve}")" if [ "$v" = fixed ]; then info "Pinned kernel $pin contains the fix" else RED=$((RED + 1)) _failed "Pinned kernel $pin has no fix: the next boot starts it again (proxmox-boot-tool kernel unpin)" fi fi fi fi header "Exposure until the fixed kernel runs" run_check info "No TCP listeners beyond loopback" \ "TCP listeners beyond loopback (IPv4 reaches dual-stack sockets too): @N@" chk_listeners if [ "$(sysctl -n net.mptcp.enabled 2>/dev/null)" = 1 ]; then run_check soft "MPTCP enabled, no MPTCP listeners" \ "MPTCP listeners, the path of the published exploit: @N@" chk_mptcp else _ok "MPTCP disabled or not available" fi run_check soft "Request socket migration off (net.ipv4.tcp_migrate_req = 0)" \ "Request socket migration on, second path of the race: @N@" chk_migrate if [ -z "$ctr" ]; then n=0 command -v pct >/dev/null && n=$(pct list 2>/dev/null | awk 'NR > 1 && $2 == "running"' | grep -c .) [ "$n" -gt 0 ] && info "Running LXC containers sharing this kernel: $n" n=0 command -v docker >/dev/null && n=$(timeout 10 docker ps -q 2>/dev/null | grep -c .) [ "$n" -gt 0 ] && info "Running Docker containers sharing this kernel: $n" fi run_check info "No nftables rule found that drops IPv4 packets with options (stopgap)" \ "nftables rules dropping IPv4 packets with options (stopgap): @N@" chk_stopgap header "Result" if [ $((RED + YELLOW)) -eq 0 ]; then _ok "Fixed, nothing to review" elif [ "$RED" -gt 0 ]; then _failed "Red: $RED, yellow: $YELLOW" else _soft "Yellow: $YELLOW, review and assess" fi info "Report: $REPORT" [ -z "$FIRST_LINE" ] || info "View all details: tail -n +$FIRST_LINE $REPORT" [ "$RED" -gt 0 ] && exit 2 [ "$YELLOW" -gt 0 ] && exit 1 exit 0 } # CVE_CHECK_LIB=1 loads the functions without running the check (used by the test bed) [ "${CVE_CHECK_LIB:-}" = 1 ] || main "$@"