#!/usr/bin/env bash

# Local enumeration and preliminary Linux LPE correlation.
# Does not load modules, change sysctls, or execute exploits.

set -uo pipefail

if [[ -t 1 && -z "${NO_COLOR:-}" ]]; then
  C_RESET=$'\033[0m'; C_BOLD=$'\033[1m'; C_DIM=$'\033[2m'
  C_RED=$'\033[38;5;196m'; C_GREEN=$'\033[38;5;82m'
  C_YELLOW=$'\033[38;5;220m'; C_CYAN=$'\033[38;5;203m'
else
  C_RESET=''; C_BOLD=''; C_DIM=''; C_GREEN=''; C_YELLOW=''; C_RED=''; C_CYAN=''
fi

declare -a R_CVE=() R_NAME=() R_STATE=() R_REASON=()

banner() {
  printf '%s%s' "$C_BOLD" "$C_RED"
  cat <<'ASCII'
 ____  _____ ____ _____ _____    _    __  __ _____ ____     _____ ____
|  _ \| ____|  _ \_   _| ____|  / \  |  \/  | ____|  _ \   | ____/ ___|
| |_) |  _| | | | || | |  _|   / _ \ | |\/| |  _| | |_) |  |  _| \___ \
|  _ <| |___| |_| || | | |___ / ___ \| |  | | |___|  _ < _ | |___ ___) |
|_| \_\_____|____/ |_| |_____/_/   \_\_|  |_|_____|_| \_(_) |_____|____/
ASCII
  printf '%s\n' "$C_RESET"
  printf '%sLinux exploit surface enumerator%s\n' "$C_DIM" "$C_RESET"
}

section() { printf '\n%s%s━━ %s ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━%s\n' "$C_BOLD" "$C_RED" "$1" "$C_RESET"; }
kv() { printf '  %s%-27s%s %s\n' "$C_CYAN" "$1" "$C_RESET" "${2:-unavailable}"; }
yesno() { [[ "$1" == "1" || "$1" == "y" || "$1" == "yes" ]] && printf 'yes' || printf 'no'; }
clean_ver() { printf '%s' "$1" | sed -E 's/^[^0-9]*//; s/[^0-9].*$//'; }
kbase() { printf '%s' "$1" | sed -E 's/^([0-9]+\.[0-9]+\.[0-9]+).*/\1/'; }
v_ge() { [[ "$(printf '%s\n%s\n' "$2" "$1" | sort -V | head -n1)" == "$2" ]]; }
v_le() { [[ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)" == "$1" ]]; }
v_between() { v_ge "$1" "$2" && v_le "$1" "$3"; }

add_result() {
  R_CVE+=("$1"); R_NAME+=("$2"); R_STATE+=("$3"); R_REASON+=("$4")
}

sysctl_read() {
  local key="$1" path value
  path="/proc/sys/${key//./\/}"
  if [[ -r "$path" ]]; then
    IFS= read -r value < "$path" || true
    printf '%s' "${value:-?}"
  else
    sysctl -n "$key" 2>/dev/null || printf '?'
  fi
}
config_value() {
  local key="$1" line=''
  if [[ -r "$KCONFIG" ]]; then line=$(grep -m1 "^${key}=" "$KCONFIG" 2>/dev/null || true)
  elif [[ -r /proc/config.gz ]] && command -v zcat >/dev/null; then line=$(zcat /proc/config.gz 2>/dev/null | grep -m1 "^${key}=" || true)
  fi
  [[ -n "$line" ]] && printf '%s' "${line#*=}" || printf '?'
}
module_state() {
  local module="$1" module_file="${1//_/-}"
  if [[ $'\n'${LOADED_MODULES//$'\n'/$'\n'} == *$'\n'"$module "* ]]; then
    printf 'loaded'
  elif [[ "$MODULE_INDEX" == *"/$module.ko"* || "$MODULE_INDEX" == *"/$module.ko."* ||
          "$MODULE_INDEX" == *"/$module_file.ko"* || "$MODULE_INDEX" == *"/$module_file.ko."* ]]; then
    printf 'available'
  else
    printf 'not detected'
  fi
}
module_present() { [[ "$(module_state "$1")" != "not detected" ]]; }

pkg_version() {
  local name="$1" value=''
  if command -v dpkg-query >/dev/null; then
    value=$(dpkg-query -W -f='${Version}' "$name" 2>/dev/null || true)
  elif command -v rpm >/dev/null; then
    value=$(rpm -q --qf '%{VERSION}-%{RELEASE}' "$name" 2>/dev/null || true)
  elif command -v pacman >/dev/null; then
    value=$(pacman -Q "$name" 2>/dev/null | awk '{print $2}' || true)
  fi
  printf '%s' "${value:-not installed}"
}

OS_ID=$(awk -F= '$1=="ID"{gsub(/"/,"",$2); print $2}' /etc/os-release 2>/dev/null || true)
OS_NAME=$(awk -F= '$1=="PRETTY_NAME"{sub(/^[^=]*=/,""); gsub(/"/,""); print}' /etc/os-release 2>/dev/null || true)
OS_VERSION=$(awk -F= '$1=="VERSION_ID"{gsub(/"/,"",$2); print $2}' /etc/os-release 2>/dev/null || true)
KERNEL=$(uname -r)
KERNEL_BASE=$(kbase "$KERNEL")
ARCH=$(uname -m)
KCONFIG="/boot/config-$KERNEL"
LOADED_MODULES=''
[[ -r /proc/modules ]] && LOADED_MODULES=$(</proc/modules)
MODULE_INDEX=''
for module_index_file in "/lib/modules/$KERNEL/modules.dep" "/lib/modules/$KERNEL/modules.builtin"; do
  [[ -r "$module_index_file" ]] && MODULE_INDEX+=$'\n'"$(<"$module_index_file")"
done

USERNS_SYSCTL=$(sysctl_read kernel.unprivileged_userns_clone)
USERNS_MAX=$(sysctl_read user.max_user_namespaces)
YAMA=$(sysctl_read kernel.yama.ptrace_scope)
AA_USERNS=$(sysctl_read kernel.apparmor_restrict_unprivileged_userns)
IOURING=$(sysctl_read kernel.io_uring_disabled)

USERNS_WORKS=0
USERNETNS_WORKS=0
USERNS_STATUS='blocked or restricted by policy'
if [[ "$USERNS_MAX" != 0 && "$USERNS_SYSCTL" != 0 && "$AA_USERNS" != 1 ]]; then
  USERNS_WORKS=1
  USERNETNS_WORKS=1
  USERNS_STATUS='policy permits unprivileged namespaces'
fi

CFG_USER_NS=$(config_value CONFIG_USER_NS)
CFG_NFT=$(config_value CONFIG_NF_TABLES)
CFG_XFRM=$(config_value CONFIG_XFRM)
CFG_RXRPC=$(config_value CONFIG_AF_RXRPC)
CFG_RXGK=$(config_value CONFIG_RXGK)
CFG_RDS=$(config_value CONFIG_RDS)
CFG_OVS=$(config_value CONFIG_OPENVSWITCH)
CFG_CIFS=$(config_value CONFIG_CIFS)
CFG_SCTP=$(config_value CONFIG_IP_SCTP)
CFG_IPV6=$(config_value CONFIG_IPV6)
CFG_BRIDGE=$(config_value CONFIG_BRIDGE)
CFG_BRIDGE_IGMP=$(config_value CONFIG_BRIDGE_IGMP_SNOOPING)
CFG_NETFILTER_QUEUE=$(config_value CONFIG_NETFILTER_NETLINK_QUEUE)
CFG_IDLETIMER=$(config_value CONFIG_NETFILTER_XT_TARGET_IDLETIMER)
CFG_SYSVIPC=$(config_value CONFIG_SYSVIPC)
CFG_CHECKPOINT=$(config_value CONFIG_CHECKPOINT_RESTORE)
CFG_IO_URING=$(config_value CONFIG_IO_URING)

SUDO_VER=$(pkg_version sudo)
SUDO_VER=${SUDO_VER:-not installed}
SNAPD_VER=$(pkg_version snapd)
PACKAGEKIT_VER=$(pkg_version packagekit)
[[ "$PACKAGEKIT_VER" == "not installed" ]] && PACKAGEKIT_VER=$(pkg_version PackageKit)
UDISKS_VER=$(pkg_version udisks2)
LIBBLOCKDEV_VER=$(pkg_version libblockdev2)
[[ "$LIBBLOCKDEV_VER" == "not installed" ]] && LIBBLOCKDEV_VER=$(pkg_version libblockdev)
CIFSUTILS_VER=$(pkg_version cifs-utils)
PAM_VER=$(pkg_version libpam-modules)
[[ "$PAM_VER" == "not installed" ]] && PAM_VER=$(pkg_version pam)

SUID_TARGET='none'
for f in /usr/bin/su /bin/su /usr/bin/sudo /usr/bin/passwd; do
  if [[ -f "$f" && -r "$f" && -u "$f" ]]; then SUID_TARGET="$f"; break; fi
done

SNAP_CONFINE='not found'; SNAP_CAPS=''; SNAP_SUID=0
for f in /usr/lib/snapd/snap-confine /usr/libexec/snapd/snap-confine; do
  if [[ -e "$f" ]]; then
    SNAP_CONFINE="$f"
    command -v getcap >/dev/null && SNAP_CAPS=$(getcap "$f" 2>/dev/null || true)
    [[ -u "$f" ]] && SNAP_SUID=1
    break
  fi
done

PAM_NAMESPACE=0
NAMESPACE_RULES=0
for pam_file in /etc/pam.d/*; do
  [[ -f "$pam_file" && -r "$pam_file" ]] || continue
  [[ "$(<"$pam_file")" == *pam_namespace.so* ]] && PAM_NAMESPACE=1
done
for namespace_file in /etc/security/namespace.conf /etc/security/namespace.d/*.conf; do
  [[ -r "$namespace_file" ]] || continue
  while IFS= read -r namespace_line; do
    [[ "$namespace_line" =~ ^[[:space:]]*(#|$) ]] || ((NAMESPACE_RULES+=1))
  done < "$namespace_file"
done

XFS_REFLINK='no XFS mount detected'
while IFS=' ' read -r _mount_src _mount_target mount_type _mount_opts _mount_rest; do
  if [[ "$mount_type" == xfs ]]; then
    XFS_REFLINK="XFS mounted at $_mount_target; reflink not passively confirmed"
    break
  fi
done < /proc/self/mounts

banner
section 'System'
kv 'User' "$(id 2>/dev/null)"
kv 'Enumeration mode' 'passive OPSEC'
kv 'Distribution' "${OS_NAME:-unknown}"
kv 'ID / version' "${OS_ID:-?} ${OS_VERSION:-?}"
kv 'Kernel' "$KERNEL"
kv 'Architecture' "$ARCH"
kv 'Kernel configuration' "$([[ -r "$KCONFIG" || -r /proc/config.gz ]] && echo available || echo inaccessible)"

section 'Namespaces and controls'
kv 'User namespace policy' "$USERNS_STATUS"
kv 'User namespace inferred' "$(yesno "$USERNS_WORKS")"
kv 'User + netns inferred' "$(yesno "$USERNETNS_WORKS")"
kv 'unprivileged_userns_clone' "$USERNS_SYSCTL"
kv 'max_user_namespaces' "$USERNS_MAX"
kv 'AppArmor restricts userns' "$AA_USERNS"
kv 'Yama ptrace_scope' "$YAMA"
kv 'io_uring_disabled' "$IOURING"

section 'Configuration and surfaces'
kv 'CONFIG_USER_NS' "$CFG_USER_NS"
kv 'CONFIG_NF_TABLES' "$CFG_NFT"
kv 'CONFIG_XFRM' "$CFG_XFRM"
kv 'CONFIG_AF_RXRPC' "$CFG_RXRPC"
kv 'CONFIG_RXGK' "$CFG_RXGK"
kv 'CONFIG_RDS' "$CFG_RDS"
kv 'CONFIG_OPENVSWITCH' "$CFG_OVS"
kv 'CONFIG_CIFS' "$CFG_CIFS"
kv 'CONFIG_IP_SCTP' "$CFG_SCTP"
kv 'CONFIG_IPV6' "$CFG_IPV6"
kv 'CONFIG_BRIDGE' "$CFG_BRIDGE"
kv 'CONFIG_BRIDGE_IGMP_SNOOPING' "$CFG_BRIDGE_IGMP"
kv 'CONFIG_NETFILTER_NETLINK_QUEUE' "$CFG_NETFILTER_QUEUE"
kv 'CONFIG_NETFILTER_XT_TARGET_IDLETIMER' "$CFG_IDLETIMER"
kv 'CONFIG_SYSVIPC' "$CFG_SYSVIPC"
kv 'CONFIG_CHECKPOINT_RESTORE' "$CFG_CHECKPOINT"
kv 'CONFIG_IO_URING' "$CFG_IO_URING"
for m in nf_tables nfnetlink_queue xt_IDLETIMER bridge br_netfilter algif_aead authencesn esp4 esp6 rxrpc rxgk rds rds_tcp act_pedit openvswitch cifs sctp; do
  kv "Module $m" "$(module_state "$m")"
done

section 'Userland components'
kv 'sudo' "$SUDO_VER"
kv 'snapd' "$SNAPD_VER"
kv 'snap-confine' "$SNAP_CONFINE"
kv 'snap-confine capabilities' "${SNAP_CAPS:-none}"
kv 'snap-confine SUID' "$(yesno "$SNAP_SUID")"
kv 'PackageKit' "$PACKAGEKIT_VER"
kv 'udisks2' "$UDISKS_VER"
kv 'libblockdev' "$LIBBLOCKDEV_VER"
kv 'cifs-utils' "$CIFSUTILS_VER"
kv 'PAM' "$PAM_VER"
kv 'pam_namespace enabled' "$(yesno "$PAM_NAMESPACE")"
kv 'Active namespace rules' "$NAMESPACE_RULES"
kv 'Readable SUID' "$SUID_TARGET"
kv 'XFS' "$XFS_REFLINK"

# Correlations are passive. CONFIRMED identifies an exact public target,
# not successful exploitation. POTENTIAL still requires patch/profile review.

if v_ge "$KERNEL_BASE" 5.7 && ! v_ge "$KERNEL_BASE" 7.1 && [[ "$CFG_IPV6" != n && "$USERNETNS_WORKS" == 1 ]]; then
  add_result 'CVE-2026-43501' 'Route of Root' 'POTENTIAL' "kernel $KERNEL + IPv6 + user/netns; requires a matching exploit profile"
else add_result 'CVE-2026-43501' 'Route of Root' 'NONE' 'outside 5.7–7.0 or IPv6/user-net namespaces are unavailable'; fi

BRIDGE_UAF='POTENTIAL'
case "$KERNEL_BASE" in
  5.10.*) v_ge "$KERNEL_BASE" 5.10.265 && BRIDGE_UAF='NONE' ;;
  5.15.*) v_ge "$KERNEL_BASE" 5.15.216 && BRIDGE_UAF='NONE' ;;
  6.1.*)  v_ge "$KERNEL_BASE" 6.1.183 && BRIDGE_UAF='NONE' ;;
  6.6.*)  v_ge "$KERNEL_BASE" 6.6.151 && BRIDGE_UAF='NONE' ;;
  6.12.*) v_ge "$KERNEL_BASE" 6.12.103 && BRIDGE_UAF='NONE' ;;
  6.18.*) v_ge "$KERNEL_BASE" 6.18.44 && BRIDGE_UAF='NONE' ;;
  7.1.*)  v_ge "$KERNEL_BASE" 7.1.8 && BRIDGE_UAF='NONE' ;;
  7.2.*)  BRIDGE_UAF='NONE' ;;
esac
if [[ "$BRIDGE_UAF" == 'POTENTIAL' && "$USERNETNS_WORKS" == 1 ]] && { module_present bridge || [[ "$CFG_BRIDGE" =~ ^(y|m)$ ]]; }; then
  add_result 'CVE-2026-74480' 'Bridge multicast UAF' 'POTENTIAL' "kernel $KERNEL + bridge + user/netns; confirm multicast settings and backport"
else add_result 'CVE-2026-74480' 'Bridge multicast UAF' 'NONE' 'fixed branch or bridge/user-net namespaces are unavailable'; fi

if [[ "$KERNEL" == *'6.19.10-300.fc43'* ]]; then
  add_result 'CVE-2026-52912' 'NFQUEUE bridge UAF' 'CONFIRMED' "exact NebuSec Fedora profile: $KERNEL"
elif [[ "$USERNETNS_WORKS" == 1 ]] && module_present bridge && module_present br_netfilter && module_present nfnetlink_queue; then
  add_result 'CVE-2026-52912' 'NFQUEUE bridge UAF' 'POTENTIAL' "bridge + br_netfilter + NFQUEUE + user/netns; profile required for $KERNEL"
else add_result 'CVE-2026-52912' 'NFQUEUE bridge UAF' 'NONE' 'required bridge/NFQUEUE/namespaces surface is missing'; fi

if [[ "$KERNEL" == *'6.12.0-211.7.3.el10_2'* ]]; then
  add_result 'CVE-2026-52923' 'SysV IPC IDR UAF' 'CONFIRMED' "exact NebuSec RHEL profile: $KERNEL"
elif [[ "$CFG_SYSVIPC" != n && "$CFG_CHECKPOINT" != n && "$USERNS_WORKS" == 1 ]]; then
  add_result 'CVE-2026-52923' 'SysV IPC IDR UAF' 'POTENTIAL' "SysV IPC + checkpoint/restore + userns; profile required for $KERNEL"
else add_result 'CVE-2026-52923' 'SysV IPC IDR UAF' 'NONE' 'SysV IPC, checkpoint/restore or user namespaces are unavailable'; fi

if v_ge "$KERNEL_BASE" 5.7 && [[ "$USERNETNS_WORKS" == 1 ]] && { module_present xt_IDLETIMER || [[ "$CFG_IDLETIMER" =~ ^(y|m)$ ]]; }; then
  add_result 'CVE-2026-23274' 'Netfilter IDLETIMER' 'POTENTIAL' "kernel $KERNEL + xt_IDLETIMER + user/netns; confirm stable fix and profile"
else add_result 'CVE-2026-23274' 'Netfilter IDLETIMER' 'NONE' 'version, xt_IDLETIMER or user-net namespaces do not match'; fi

if [[ "$OS_ID" == ubuntu && "$KERNEL" == '7.0.0-28-generic' ]]; then
  add_result 'CVE-2026-52929' 'SCTP stream rollback' 'CONFIRMED' "exact NebuSec Ubuntu profile: $KERNEL"
elif module_present sctp || [[ "$CFG_SCTP" =~ ^(y|m)$ ]]; then
  add_result 'CVE-2026-52929' 'SCTP stream rollback' 'POTENTIAL' "SCTP present; exact profile and vendor patch required for $KERNEL"
else add_result 'CVE-2026-52929' 'SCTP stream rollback' 'NONE' 'SCTP was not detected'; fi

if [[ "$KERNEL" == *'6.19.10-300.fc43'* && "$ARCH" == x86_64 && "$IOURING" != 2 ]]; then
  add_result 'CVE-2026-52933' 'io_uring poll_refs' 'CONFIRMED' "exact NebuSec Fedora profile; full chain requires approximately 2^30 wakeups"
elif [[ "$CFG_IO_URING" != n && "$IOURING" != 2 ]]; then
  add_result 'CVE-2026-52933' 'io_uring poll_refs' 'POTENTIAL' "io_uring enabled on $KERNEL; confirm fix and exact profile"
else add_result 'CVE-2026-52933' 'io_uring poll_refs' 'NONE' 'io_uring is disabled or absent'; fi

if v_between "$KERNEL_BASE" 5.14 6.6.99 && [[ "$USERNS_WORKS" == 1 ]] && module_present nf_tables; then
  add_result 'CVE-2024-1086' 'nf_tables UAF' 'POTENTIAL' "kernel $KERNEL; userns; nf_tables; verify vendor backport"
else add_result 'CVE-2024-1086' 'nf_tables UAF' 'NONE' '5.14–6.6 range and/or prerequisites do not match'; fi

if [[ "$OS_ID" =~ (opensuse|sles|suse) && "$OS_VERSION" == 15* && "$UDISKS_VER" != 'not installed' && "$LIBBLOCKDEV_VER" != 'not installed' ]]; then
  add_result 'CVE-2025-6018/6019' 'SUSE PAM + udisks' 'POTENTIAL' 'SUSE 15 with udisks/libblockdev; check allow_active and vendor patch'
else add_result 'CVE-2025-6018/6019' 'SUSE PAM + udisks' 'NONE' 'SUSE 15 stack does not match'; fi

if [[ "$PAM_NAMESPACE" == 1 && "$NAMESPACE_RULES" -gt 0 ]]; then
  add_result 'CVE-2025-6020/8941' 'pam_namespace' 'POTENTIAL' "$NAMESPACE_RULES active rules; inspect user-controlled paths and complete fix"
else add_result 'CVE-2025-6020/8941' 'pam_namespace' 'NONE' 'pam_namespace has no active configuration'; fi

if [[ "$SUDO_VER" != 'not installed' ]] && v_ge "$SUDO_VER" 1.9.14 && ! v_ge "$SUDO_VER" 1.9.17p1; then
  add_result 'CVE-2025-32463' 'sudo --chroot' 'POTENTIAL' "sudo $SUDO_VER; verify vendor backport"
else add_result 'CVE-2025-32463' 'sudo --chroot' 'NONE' "sudo $SUDO_VER is outside the upstream range"; fi

SNAP_3888=0
if command -v dpkg >/dev/null && [[ "$SNAPD_VER" != 'not installed' ]]; then
  case "$OS_VERSION" in
    24.04) dpkg --compare-versions "$SNAPD_VER" lt '2.73+ubuntu24.04.2' && SNAP_3888=1 ;;
    25.10) dpkg --compare-versions "$SNAPD_VER" lt '2.73+ubuntu25.10.1' && SNAP_3888=1 ;;
    26.04) dpkg --compare-versions "$SNAPD_VER" lt '2.74.1+ubuntu26.04.1' && SNAP_3888=1 ;;
  esac
fi
if [[ "$OS_ID" == ubuntu && "$SNAP_3888" == 1 ]]; then
  add_result 'CVE-2026-3888' 'snap-confine + tmpfiles' 'POTENTIAL' "Ubuntu $OS_VERSION, snapd $SNAPD_VER predates the fixed package"
else add_result 'CVE-2026-3888' 'snap-confine + tmpfiles' 'NONE' "Ubuntu ${OS_VERSION:-?}, snapd $SNAPD_VER"; fi

PK_NUM=$(printf '%s' "$PACKAGEKIT_VER" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)
if [[ -n "$PK_NUM" ]] && v_ge "$PK_NUM" 1.0.2 && ! v_ge "$PK_NUM" 1.3.5; then
  add_result 'CVE-2026-41651' 'Pack2TheRoot' 'POTENTIAL' "PackageKit $PACKAGEKIT_VER (range 1.0.2–1.3.4); verify vendor backport"
else add_result 'CVE-2026-41651' 'Pack2TheRoot' 'NONE' "PackageKit $PACKAGEKIT_VER"; fi

if v_between "$KERNEL_BASE" 6.0 6.18.99 && module_present algif_aead && module_present authencesn && [[ "$SUID_TARGET" != none ]]; then
  add_result 'CVE-2026-31431' 'Copy Fail' 'POTENTIAL' "kernel $KERNEL + algif_aead/authencesn + SUID; verify backport"
else add_result 'CVE-2026-31431' 'Copy Fail' 'NONE' 'outside 6.0–6.18 or required modules/SUID are missing'; fi

if module_present esp4 && module_present esp6 && module_present rxrpc && [[ "$USERNS_WORKS" == 1 && "$SUID_TARGET" != none ]]; then
  add_result 'CVE-2026-43284/43500' 'Dirty Frag' 'POTENTIAL' 'ESP + RxRPC + userns + SUID; verify the complete fix chain'
else add_result 'CVE-2026-43284/43500' 'Dirty Frag' 'NONE' 'required surfaces are missing'; fi

if module_present esp4 && [[ "$CFG_XFRM" != n && "$USERNS_WORKS" == 1 && "$SUID_TARGET" != none ]]; then
  add_result 'CVE-2026-46300' 'Fragnesia' 'POTENTIAL' 'XFRM/ESP + userns + SUID; confirm ESP-in-TCP and vendor patch'
else add_result 'CVE-2026-46300' 'Fragnesia' 'NONE' 'XFRM/ESP, userns or SUID is missing'; fi

if v_between "$KERNEL_BASE" 6.10 6.13.99 && { [[ "$CFG_RXGK" =~ ^(y|m)$ ]] || module_present rxgk; }; then
  add_result 'CVE-2026-31635' 'DirtyDecrypt' 'POTENTIAL' "kernel $KERNEL and RxGK; confirm backport"
else add_result 'CVE-2026-31635' 'DirtyDecrypt' 'NONE' 'outside 6.10–6.13 or RxGK was not detected'; fi

if module_present rds && module_present rds_tcp && [[ "$IOURING" != 2 && "$ARCH" == x86_64 && "$SUID_TARGET" != none ]]; then
  add_result 'CVE-2026-43494' 'PinTheft' 'POTENTIAL' 'RDS + io_uring + x86-64 + SUID; requires a matching kernel profile'
else add_result 'CVE-2026-43494' 'PinTheft' 'NONE' 'RDS/io_uring/x86-64/SUID prerequisites are missing'; fi

if [[ "$YAMA" == 1 || "$YAMA" == 0 ]]; then
  add_result 'CVE-2026-46333' 'ptrace exit race' 'POTENTIAL' "ptrace_scope=$YAMA; confirm commit 31e62c2ebbfd in the vendor kernel"
else add_result 'CVE-2026-46333' 'ptrace exit race' 'NONE' "ptrace_scope=$YAMA"; fi

if [[ "$CIFSUTILS_VER" != 'not installed' ]] && module_present cifs && [[ "$USERNS_WORKS" == 1 ]]; then
  add_result 'CVE-2026-46243' 'CIFSwitch' 'POTENTIAL' 'cifs-utils + CIFS + userns; confirm patch and keyring policy'
else add_result 'CVE-2026-46243' 'CIFSwitch' 'NONE' 'cifs-utils/CIFS/userns prerequisites are missing'; fi

if module_present nf_tables && [[ "$USERNS_WORKS" == 1 ]]; then
  add_result 'CVE-2026-23111' 'nftables genmask UAF' 'POTENTIAL' "nf_tables + userns; kernel $KERNEL requires exact patch verification"
else add_result 'CVE-2026-23111' 'nftables genmask UAF' 'NONE' 'nf_tables or userns is unavailable'; fi

if [[ "$USERNS_WORKS" == 1 && "$SUID_TARGET" != none ]]; then
  add_result 'CVE-2026-43503' 'DirtyClone' 'POTENTIAL' 'userns + SUID; verify all four Dirty Frag patches'
else add_result 'CVE-2026-43503' 'DirtyClone' 'NONE' 'userns or SUID is missing'; fi

if module_present act_pedit && [[ "$USERNETNS_WORKS" == 1 && "$SUID_TARGET" != none ]] && v_ge "$KERNEL_BASE" 5.18; then
  add_result 'CVE-2026-46331' 'pedit COW' 'POTENTIAL' "act_pedit + user/netns + SUID; kernel $KERNEL"
else add_result 'CVE-2026-46331' 'pedit COW' 'NONE' 'act_pedit, namespaces, SUID or version range is missing'; fi

if [[ "$ARCH" == x86_64 ]]; then
  add_result 'CVE-2026-43499' 'GhostLock' 'POTENTIAL' "x86-64 kernel $KERNEL; only use an exact supported profile"
else add_result 'CVE-2026-43499' 'GhostLock' 'POTENTIAL' "architecture $ARCH; requires a port and exact offsets"; fi

if [[ -n "$SNAP_CAPS" && "$SNAP_SUID" == 0 ]]; then
  add_result 'CVE-2026-8933' 'snap-confine capabilities' 'POTENTIAL' "snap-confine uses file capabilities; snapd $SNAPD_VER"
else add_result 'CVE-2026-8933' 'snap-confine capabilities' 'NONE' 'file-capability variant was not detected'; fi

if [[ "$XFS_REFLINK" == 'reflink=1' ]]; then
  add_result 'CVE-2026-64600' 'RefluXFS' 'POTENTIAL' 'XFS reflink=1; confirm kernel backport'
elif [[ "$XFS_REFLINK" == XFS\ mounted* ]]; then
  add_result 'CVE-2026-64600' 'RefluXFS' 'POTENTIAL' "$XFS_REFLINK; verify reflink=1 separately"
else add_result 'CVE-2026-64600' 'RefluXFS' 'NONE' "$XFS_REFLINK"; fi

if module_present openvswitch && [[ "$USERNETNS_WORKS" == 1 ]]; then
  add_result 'CVE-2026-64531' 'OVSwrap' 'POTENTIAL' 'Open vSwitch + user/netns; verify profile and kernel patch'
else add_result 'CVE-2026-64531' 'OVSwrap' 'NONE' 'Open vSwitch or user/netns is unavailable'; fi

if [[ "$ARCH" == x86_64 && "$SUID_TARGET" != none ]]; then
  add_result 'CVE-2026-53361' 'BadGarbage' 'POTENTIAL' "AF_UNIX present; check whether $KERNEL has a supported profile and fix"
else add_result 'CVE-2026-53361' 'BadGarbage' 'NONE' 'architecture/target does not match'; fi

if v_ge "$KERNEL_BASE" 6.4; then
  add_result 'CVE-2026-46242' 'Bad Epoll' 'POTENTIAL' "kernel $KERNEL >= 6.4; confirm a6dc643c6931 backport and supported profile"
else add_result 'CVE-2026-46242' 'Bad Epoll' 'NONE' 'the bug was introduced in Linux 6.4'; fi

TC_UAF='POTENTIAL'
case "$KERNEL_BASE" in
  5.10.*) v_ge "$KERNEL_BASE" 5.10.259 && TC_UAF='NONE' ;;
  5.15.*) v_ge "$KERNEL_BASE" 5.15.210 && TC_UAF='NONE' ;;
  6.1.*)  v_ge "$KERNEL_BASE" 6.1.176 && TC_UAF='NONE' ;;
  6.6.*)  v_ge "$KERNEL_BASE" 6.6.143 && TC_UAF='NONE' ;;
  6.12.*) v_ge "$KERNEL_BASE" 6.12.94 && TC_UAF='NONE' ;;
  6.18.*) v_ge "$KERNEL_BASE" 6.18.36 && TC_UAF='NONE' ;;
  7.0.*)  v_ge "$KERNEL_BASE" 7.0.13 && TC_UAF='NONE' ;;
esac
if [[ "$TC_UAF" == 'POTENTIAL' ]] && module_present act_pedit; then
  PT_STATE='not detected'; [[ -e /sys/bus/event_source/devices/intel_pt ]] && PT_STATE='Intel PT available'
  add_result 'CVE-2026-53264' 'TC action UAF' 'POTENTIAL' "act_pedit; $PT_STATE; public exploit targets CentOS Stream 9"
else add_result 'CVE-2026-53264' 'TC action UAF' 'NONE' 'upstream branch is fixed or traffic control was not detected'; fi

if module_present sctp || [[ "$CFG_SCTP" =~ ^(y|m)$ ]]; then
  add_result 'CVE-2026-64564' 'SCTPhantom' 'POTENTIAL' "SCTP available on $KERNEL; confirm 9b2854f86f0b backport"
else add_result 'CVE-2026-64564' 'SCTPhantom' 'NONE' 'SCTP was not detected'; fi

XFRM_DF='NONE'
if v_ge "$KERNEL_BASE" 6.11 && ! v_ge "$KERNEL_BASE" 7.2; then
  case "$KERNEL_BASE" in
    6.12.*) v_ge "$KERNEL_BASE" 6.12.101 || XFRM_DF='POTENTIAL' ;;
    6.18.*) v_ge "$KERNEL_BASE" 6.18.40 || XFRM_DF='POTENTIAL' ;;
    7.1.*)  v_ge "$KERNEL_BASE" 7.1.5 || XFRM_DF='POTENTIAL' ;;
    *) XFRM_DF='POTENTIAL' ;;
  esac
fi
if [[ "$XFRM_DF" == 'POTENTIAL' && "$CFG_XFRM" != n ]]; then
  add_result 'CVE-2026-72137' 'XFRM keepalive DF' 'POTENTIAL' "kernel $KERNEL + XFRM; confirm 226f4a4/vendor backport"
else add_result 'CVE-2026-72137' 'XFRM keepalive DF' 'NONE' 'outside upstream range or XFRM is disabled'; fi

section 'Potential exploits'
printf '  %s%-22s %-25s %-12s %s%s\n' "$C_BOLD" 'CVE' 'Exploit' 'Status' 'Evidence' "$C_RESET"
printf '  %-22s %-25s %-12s %s\n' '──────────────────────' '─────────────────────────' '────────────' '────────────────────────────────────────'
for i in "${!R_CVE[@]}"; do
  case "${R_STATE[$i]}" in
    CONFIRMED) color="$C_RED" ;;
    POTENTIAL) color="$C_YELLOW" ;;
    *) color="$C_DIM" ;;
  esac
  printf '  %-22s %-25s %s%-12s%s %s\n' \
    "${R_CVE[$i]}" "${R_NAME[$i]}" "$color" "${R_STATE[$i]}" "$C_RESET" "${R_REASON[$i]}"
done

printf '\n%sLegend:%s CONFIRMED = exact public exploit target; POTENTIAL = passive correlation, verify vendor patch/profile; NONE = fixed range or missing prerequisite.\n' "$C_BOLD" "$C_RESET"
