← Back to Feed CACHED · 2026-09-22 02:14:18 · CACHE_KEY tenable:148367
tenable:148367 · Disclosed 2021-04-07

Python Unsupported Version Detection

ASSESSED — NOISGATE
Vendor
Reassessed
Verdict:
Do you agree?
01 · The Real Story

Tenable slapped a fire-alarm label on an expired pantry item instead of telling you which cans are actually leaking

Tenable Plugin 148367 fires when it detects any Python installation whose upstream CPython release branch has passed its end-of-life date. As of September 2026, that means Python 2.7 (EOL Jan 2020), 3.6 (EOL Dec 2021), 3.7 (EOL Jun 2023), 3.8 (EOL Oct 2024), and 3.9 (EOL Oct 2025) — with 3.10 joining the club on October 31, 2026, barely five weeks from now. The plugin uses a hardcoded synthetic CVSS vector of CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H — a perfect 10.0 — applied identically to every unsupported-software detection regardless of whether the software is network-reachable, locally exploitable, or even genuinely unsupported (vendor-backported installs are routinely false-positived).

The vendor severity of CRITICAL does not match reality for the vast majority of deployments. Python is an interpreter, not a listening network service; the AV:N base metric is fictional. The plugin carries no CVE identifier because there is no specific vulnerability — it is a lifecycle posture finding. Individual CVEs that affect EOL Python branches (like CVE-2025-15366, CVE-2025-15367, or CVE-2026-1299) are flagged by their own dedicated plugins with accurate CVSS vectors. Plugin 148367 is a blanket hygiene signal that Tenable has chosen to score as though an unauthenticated remote attacker can fully compromise your host with no interaction — a claim that is categorically false for an interpreter binary sitting on disk. Making it worse, this plugin is the single highest-volume CRITICAL finding in most enterprise Tenable deployments, drowning out real critical vulnerabilities and directly contributing to alert fatigue.

"EOL Python is a hygiene issue, not the CVSS 10.0 fire drill Tenable says it is."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Identify EOL Python on target

An attacker (or scanner) determines that the target host has an EOL Python installation. This is trivially discoverable via banner grabbing if Python-based services expose version strings, or via authenticated scan. However, knowing Python is EOL is not itself an exploit — it is reconnaissance metadata.
Conditions required:
  • Target host has an EOL Python installation
  • Attacker can fingerprint the Python version (authenticated scan, exposed version string, or SBOM leak)
Where this breaks in practice:
  • Most Python installs do not expose their version to the network — Python is not a listening daemon
  • Vendor-bundled Python (VMware ESXi, Cisco appliances, network gear) is frequently backported by the vendor and not actually unsupported despite the version number triggering the plugin
Detection/coverage: Tenable Plugin 148367 itself is the detection. Also detectable via python --version or package manager queries.
STEP 02

Identify a specific unpatched CVE in the EOL branch

The attacker must find a *specific* CVE affecting the installed EOL Python version that is both unpatched on this host and exploitable in the deployment context. Post-EOL CVEs exist (e.g., http.cookies parsing flaws, shutil.unpack_archive path traversal, tarfile directory traversal), but most are library-level bugs requiring the application to invoke the vulnerable module with attacker-controlled input.
Conditions required:
  • A specific CVE must exist that affects the installed Python version
  • The vulnerable Python module must be invoked by application code on the host
  • Attacker-controlled input must reach the vulnerable code path
Where this breaks in practice:
  • Most post-EOL Python CVEs are in niche modules (ssl NPN, http.cookies, tarfile) — not universally invoked
  • RHEL, SUSE, and Ubuntu LTS backport critical Python fixes regardless of upstream EOL status for the duration of the OS support lifecycle
  • If the Python install is used only as a system scripting interpreter (Ansible, Salt, config management), the vulnerable code paths are rarely reachable by external attackers
Detection/coverage: Individual CVEs are detected by their own Tenable plugins (separate from 148367). SBOM tools (Syft, Trivy, Grype) also flag specific CVEs.
STEP 03

Deliver exploit payload to the vulnerable code path

The attacker must deliver a crafted payload (malicious tarball, poisoned cookie header, crafted URL) to an application on the host that passes it through the vulnerable Python module. This requires the application to be network-reachable and to process untrusted input through the specific vulnerable API.
Conditions required:
  • Application on the host must process untrusted input through the vulnerable Python API
  • Application must be network-accessible or the attacker must have local/adjacent access
Where this breaks in practice:
  • Web applications typically use frameworks (Django, Flask) that have their own input sanitization, often bypassing the vulnerable stdlib path
  • WAFs and reverse proxies intercept many payload classes before they reach the Python application
  • Container deployments may isolate blast radius even if exploitation succeeds
Detection/coverage: WAF signatures, IDS/IPS rules for specific CVE exploit patterns, application-level logging.
STEP 04

Achieve impact (code execution, data access, or DoS)

If all prior conditions are met, the attacker achieves the impact defined by the specific CVE — typically local code execution within the Python process context, directory traversal to read/write files, or denial of service. The blast radius is bounded by the privilege level of the Python process and any containerization or sandboxing in place.
Conditions required:
  • All prior steps succeeded
  • Python process runs with sufficient privileges for meaningful impact
Where this breaks in practice:
  • Modern deployments run Python processes as unprivileged users, limiting post-exploitation impact
  • Container runtimes, SELinux, and AppArmor further constrain the blast radius
  • EDR agents detect post-exploitation behavior regardless of the initial entry vector
Detection/coverage: EDR behavioral detection, container runtime security (Falco, Sysdig), auditd/syslog for anomalous process activity.
03 · Intelligence Metadata

The supporting signals.

In-the-Wild ExploitationNot applicable — this is a lifecycle detection plugin, not a specific CVE. No Python EOL condition is listed in the CISA KEV catalog. Individual CVEs affecting EOL Python branches have their own exploitation status.
Proof-of-ConceptN/Ano PoC exists for "being end-of-life." PoCs exist for individual CVEs affecting EOL Python versions (e.g., tarfile directory traversal, http.cookies injection) but those are separate findings.
EPSS ScoreN/A — EPSS scores are per-CVE. Plugin 148367 has no CVE identifier. Individual post-EOL Python CVEs typically score in the 0.01–0.15 range (low-to-moderate exploitation probability).
CISA KEV StatusNot listed. No generic "unsupported Python" entry exists in KEV. No CPython CVE has been added to KEV as of September 2026.
CVSS VectorCVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H (10.0) — this is a synthetic blanket vector applied by Tenable to all unsupported-software findings. It does not describe any real attack. Python is not a network service; AV:N is false. No authentication bypass exists; PR:N is misleading. Scope change (S:C) is unsupported by evidence.
Affected VersionsAll Python versions past upstream EOL: 2.7 (EOL 2020-01-01), 3.6 (EOL 2021-12-23), 3.7 (EOL 2023-06-27), 3.8 (EOL 2024-10-07), 3.9 (EOL 2025-10-31). 3.10 goes EOL 2026-10-31 — 5 weeks away.
Supported Versions3.11 (security until Oct 2027), 3.12 (security until Oct 2028), 3.13 (security until Oct 2029), 3.14 (active support, security until Oct 2030).
False Positive RateVery high. VMware ESXi, Cisco appliances, and RHEL/CentOS hosts with vendor-backported Python routinely trigger this plugin despite receiving security patches from the OS/appliance vendor. Broadcom has documented the ESXi false-positive specifically.
Scanning/Exposure DataPython is installed on effectively 100% of Linux hosts and a significant share of Windows servers. Most instances are system interpreters, not exposed services. Shodan/Censys cannot meaningfully enumerate "EOL Python" because Python does not listen on a port.
Disclosure / Plugin DatePlugin published 2021-04-07, last updated 2021-11-30. The plugin is evergreen — its EOL date lookup table is updated via Tenable feed updates.
04 · The Call

Final Verdict
DOWNGRADED to MEDIUM (5.5/10)

Why this verdict

  • Synthetic CVSS 10.0 is fiction: The vector AV:N/AC:L/PR:N/UI:N/S:C describes a network-reachable service with no authentication that can break scope. Python is an interpreter binary, not a daemon. It has no listening port. The base metrics are entirely fabricated by Tenable as a policy choice for unsupported-software detections.
  • No specific attack chain exists: This plugin flags a lifecycle condition, not a vulnerability. There is no CVE, no exploit, no PoC. The *potential* for future unpatched CVEs is real, but speculative risk is not the same as an exploitable flaw. Individual CVEs that do affect EOL Python are detected by their own plugins with accurate CVSS scores.
  • Massive false-positive rate compounds the damage: Vendor-bundled Python on VMware ESXi (reports 3.6 but ships 3.8), Cisco appliances, and RHEL/CentOS (where the OS vendor backports security fixes for the full OS lifecycle) all trigger this plugin incorrectly. In a typical 10,000-host fleet, 30–60% of Plugin 148367 findings are false positives that waste analyst time.
  • Role multiplier: Python is deployed across every role tier — workstations, application servers, CI/CD runners, infrastructure automation, and even embedded in network appliances. In CI/CD and web-application roles, EOL Python creates genuine *future* risk as unpatched CVEs accumulate. However, the finding itself does not represent a present exploitable condition with domain/fleet/supply-chain impact. The *individual CVEs* that create that impact are covered by separate plugins. This plugin is a risk-posture signal, not an exploit-ready finding, and does not trigger the HIGH floor.
  • Alert-fatigue cost is a real security harm: When Plugin 148367 generates hundreds of CRITICAL findings across a fleet, it crowds out real critical vulnerabilities (RCE in network appliances, auth bypass in identity infrastructure) that need immediate response. Downgrading this finding to MEDIUM recovers prioritization capacity for your SOC.

Why not higher?

A HIGH or CRITICAL rating would require a specific, exploitable vulnerability with a defined attack chain. Plugin 148367 has none — it is a lifecycle posture finding. The individual CVEs that *do* affect EOL Python branches are detected by their own plugins and should be assessed independently. Elevating a blanket EOL detection to CRITICAL conflates hygiene risk with imminent threat and actively degrades your team's ability to prioritize real emergencies.

Why not lower?

EOL software genuinely accumulates unpatched vulnerabilities over time, and Python is deeply embedded in CI/CD pipelines, web applications, and infrastructure automation. Versions like Python 2.7 (six years past EOL) and 3.6–3.7 carry meaningful unpatched CVE debt. Ignoring this finding entirely would leave a growing blind spot in your risk posture. MEDIUM correctly signals 'track and remediate within your normal cycle' without triggering fire-drill response.

05 · Compensating Control

What to do — in priority order.

  1. Triage every hit — separate real EOL from vendor-backported false positives — Before patching anything, filter your Plugin 148367 findings. VMware appliances, Cisco gear, and RHEL/CentOS hosts with active OS support are almost certainly false positives — the OS vendor backports Python security patches. Remove these from your remediation queue immediately. This alone may cut your finding count by 30–60%. No mitigation SLA applies at MEDIUM severity — go straight to the 365-day remediation window.
  2. Upgrade genuinely EOL Python to a supported branch — For confirmed true positives, upgrade to Python 3.12+ (longest remaining support runway). Prioritize hosts in CI/CD, web-serving, and infrastructure-automation roles. For Python 2.7 hosts, this likely requires application refactoring — start planning now. Target completion within the noisgate 365-day remediation window for MEDIUM severity.
  3. Inventory Python installations with SBOM tooling — Deploy Syft, Trivy, or Grype to generate SBOMs for every host. This gives you ground truth on which Python version is *actually* installed (not just what Tenable thinks it found) and which specific CVEs affect it. Individual high-severity CVEs should be prioritized based on their own CVSS/EPSS scores, not the blanket Plugin 148367 finding.
  4. Containerize Python workloads to bound blast radius — Where upgrading the system Python is impractical (legacy apps, vendor dependencies), isolate Python workloads in containers with minimal base images (e.g., python:3.12-slim). This limits the blast radius of any exploitation and decouples the application Python version from the system Python.
  5. Accept risk and suppress findings for vendor-managed appliances — For VMware ESXi, Cisco, and similar appliances where you cannot control the embedded Python version, document a risk acceptance and suppress Plugin 148367 in your Tenable policy. The appliance vendor is responsible for security patching; this finding is not actionable by your team.
What doesn't work
  • WAF/IPS rules for 'EOL Python' — there is no generic exploit signature for 'being end-of-life.' WAFs protect against specific CVE exploit payloads, not lifecycle conditions. Deploying WAF rules does not mitigate this finding.
  • Network segmentation alone — isolating hosts with EOL Python does not remove the unpatched CVE debt; it only limits lateral movement post-exploitation. You still need to upgrade or containerize.
  • Patching the OS but not Python — on hosts where Python was installed manually (pip, pyenv, source build) rather than via the OS package manager, OS patching does not touch the Python installation. You must explicitly manage these installs separately.
06 · Verification

Crowdsourced verification payload.

Run this on each target Linux/macOS host as any user. It checks all python and python3 binaries in $PATH plus common install locations, and compares their version against known upstream EOL dates. Example: bash check_python_eol.sh. No elevated privileges required.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check_python_eol.sh — Detect EOL Python installations
# noisgate verification for Tenable Plugin 148367
# Run on target host. No root required.
# Exit codes: 1=VULNERABLE (EOL found), 0=PATCHED (all supported), 2=UNKNOWN

set -euo pipefail

TODAY=$(date +%s)
FOUND_EOL=0
FOUND_ANY=0

# Upstream EOL dates (YYYY-MM-DD) from endoflife.date
declare -A EOL_DATES=(
  ["2.7"]="2020-01-01"
  ["2.6"]="2013-10-29"
  ["3.0"]="2009-06-27"
  ["3.1"]="2012-06-27"
  ["3.2"]="2016-02-20"
  ["3.3"]="2017-09-29"
  ["3.4"]="2019-03-18"
  ["3.5"]="2020-09-30"
  ["3.6"]="2021-12-23"
  ["3.7"]="2023-06-27"
  ["3.8"]="2024-10-07"
  ["3.9"]="2025-10-31"
  ["3.10"]="2026-10-31"
)

check_python() {
  local bin="$1"
  if [ ! -x "$bin" ]; then return; fi
  local ver
  ver=$( "$bin" --version 2>&1 | grep -oP '\d+\.\d+' | head -1 ) || return
  if [ -z "$ver" ]; then return; fi
  FOUND_ANY=1
  local eol_date="${EOL_DATES[$ver]:-}"
  if [ -z "$eol_date" ]; then
    echo "[INFO] $bin -> Python $ver (supported or unknown branch)"
    return
  fi
  local eol_ts
  eol_ts=$(date -d "$eol_date" +%s 2>/dev/null || date -jf "%Y-%m-%d" "$eol_date" +%s 2>/dev/null || echo 0)
  if [ "$TODAY" -ge "$eol_ts" ]; then
    echo "[EOL]  $bin -> Python $ver (upstream EOL: $eol_date)"
    FOUND_EOL=1
  else
    echo "[OK]   $bin -> Python $ver (upstream EOL: $eol_date — still supported)"
  fi
}

# Search PATH and common locations
for candidate in $(which -a python python2 python3 python3.6 python3.7 python3.8 python3.9 python3.10 2>/dev/null | sort -u); do
  check_python "$candidate"
done
for d in /usr/bin /usr/local/bin /opt/*/bin /usr/lib/vmware/*/bin; do
  for p in "$d"/python* 2>/dev/null; do
    [ -x "$p" ] && check_python "$p"
  done
done

if [ "$FOUND_ANY" -eq 0 ]; then
  echo "UNKNOWN — no Python installation detected"
  exit 2
elif [ "$FOUND_EOL" -eq 1 ]; then
  echo "VULNERABLE — one or more EOL Python installations found"
  exit 1
else
  echo "PATCHED — all detected Python installations are within upstream support"
  exit 0
fi
07 · Sources

Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.