Posted on
Artificial Intelligence

Artificial Intelligence Enterprise Patch Management

Author
  • User
    linuxbash
    Posts by this author
    Posts by this author

Artificial Intelligence for Enterprise Patch Management: A Bash-First Playbook

If your patch backlog grows faster than you can ship updates, you’re not alone. Attackers weaponize new CVEs in hours, while enterprises juggle uptime, change windows, and compliance. The result: risky delays and noisy spreadsheets. Good news—you can inject “AI” into your patch pipeline today with the tools you already use on Linux: Bash, curl, jq, and your native package manager. This article shows you how to prioritize, test, and automate patches using data-driven signals (KEV, EPSS) and safe rollouts.

What you’ll get:

  • A practical, Bash-first approach to “AI-assisted” patching

  • 3–5 concrete steps with copy/paste snippets

  • Install instructions for apt, dnf, and zypper

  • A minimal, reproducible pipeline you can extend

Why this works (and why now)

  • Exploitation is faster than ever. Public datasets like CISA KEV and FIRST EPSS let you rank risk by exploitation likelihood and reality, not just CVSS.

  • Native package managers already expose security advisory metadata—use it.

  • Containers make it cheap to test patches before production.

  • Lightweight scoring and automation yield 80% of the value without heavy ML lift.

“AI” here means: programmatically combining multiple risk signals (KEV, EPSS, severity) plus your environment context (internet-facing, business critical) to decide what to patch first—and automating the boring parts.


Prerequisites (install these first)

We’ll use curl, jq, and optionally podman. Choose your distro’s package manager:

Debian/Ubuntu (apt):

sudo apt update
sudo apt install -y curl jq podman python3 python3-pip git

Fedora/RHEL/CentOS Stream (dnf):

sudo dnf install -y curl jq podman python3 python3-pip git

openSUSE/SLES (zypper):

sudo zypper refresh
sudo zypper install -y curl jq podman python3 python3-pip git

Note: If podman isn’t available in your repo, use Docker instead; commands are similar.


1) Inventory and normalize: know what you can patch

Before you prioritize, map what’s installed and what’s exposed.

Export basic host and package facts:

#!/usr/bin/env bash
set -euo pipefail

HOST_JSON=/var/tmp/asset-inventory.json

distro="$(. /etc/os-release; echo "${ID}-${VERSION_ID:-unknown}")"
hostname="$(hostname -f || hostname)"
kernel="$(uname -r)"

# Running internet-facing listeners (TCP)
listeners="$(ss -lntp | awk 'NR>1 {print $4,$7}' | sed 's/,,/,/g' | sed 's/users://g' | tr -s " " | cut -d" " -f1,2)"

# Package summaries by manager
if command -v apt >/dev/null 2>&1; then
  pkg_count="$(dpkg -l | awk '/^ii/ {c++} END{print c+0}')"
elif command -v dnf >/dev/null 2>&1; then
  pkg_count="$(rpm -qa | wc -l)"
elif command -v zypper >/dev/null 2>&1; then
  pkg_count="$(rpm -qa | wc -l)"
else
  pkg_count="unknown"
fi

jq -n --arg host "$hostname" \
      --arg distro "$distro" \
      --arg kernel "$kernel" \
      --arg listeners "$listeners" \
      --argjson pkg_count "$pkg_count" \
'{
  host:$host,
  distro:$distro,
  kernel:$kernel,
  pkg_count:$pkg_count,
  listeners:$listeners | split("\n") | map(select(length>0))
}' | tee "$HOST_JSON"

Tip: Tag which listeners are internet-facing (e.g., 0.0.0.0:443 or public IPs) and mark those hosts “exposed=true” in your CMDB or this JSON. You’ll weight those higher later.


2) Build an AI-assisted risk score with KEV + EPSS

We’ll:

  • Collect CVEs tied to your pending security updates (per-distro)

  • Join them with:

    • CISA KEV (is it known-exploited?)
    • FIRST EPSS (probability of exploitation)
  • Produce a priority list

First, helper scripts to get “security updates → CVEs”:

For apt (Debian/Ubuntu):

#!/usr/bin/env bash
# get_cves_apt.sh
set -euo pipefail
sudo apt update >/dev/null
# List upgradable packages, fetch changelogs, grep CVEs
apt list --upgradable 2>/dev/null | awk -F/ 'NR>1{print $1}' | while read -r pkg; do
  sudo apt-get -qq changelog "$pkg" 2>/dev/null | grep -Eo 'CVE-[0-9]{4}-[0-9]+' || true
done | sort -u

For dnf (Fedora/RHEL/CentOS Stream):

#!/usr/bin/env bash
# get_cves_dnf.sh
set -euo pipefail
sudo dnf makecache >/dev/null
# List security advisories and extract CVEs
sudo dnf updateinfo info --security 2>/dev/null | grep -Eo 'CVE-[0-9]{4}-[0-9]+' | sort -u

For zypper (openSUSE/SLES):

#!/usr/bin/env bash
# get_cves_zypper.sh
set -euo pipefail
sudo zypper refresh >/dev/null
# List patches with CVEs (supported on modern zypper)
sudo zypper list-patches --cve 2>/dev/null | grep -Eo 'CVE-[0-9]{4}-[0-9]+' | sort -u

Now, fetch KEV and EPSS, join, and score:

#!/usr/bin/env bash
# prioritize_cves.sh
set -euo pipefail

TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT

# Pick the right CVE collector
if command -v apt >/dev/null 2>&1; then
  CVES=($("./get_cves_apt.sh"))
elif command -v dnf >/dev/null 2>&1; then
  CVES=($("./get_cves_dnf.sh"))
elif command -v zypper >/dev/null 2>&1; then
  CVES=($("./get_cves_zypper.sh"))
else
  echo "No supported package manager found." >&2; exit 1
fi

if [ ${#CVES[@]} -eq 0 ]; then
  echo "No CVEs associated with pending updates."; exit 0
fi

# Download KEV catalog (Known Exploited Vulnerabilities)
curl -fsSL https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json \
  -o "$TMP_DIR/kev.json"

# Function to query EPSS API for one CVE
get_epss() {
  local cve="$1"
  curl -fsSL "https://api.first.org/data/v1/epss?cve=${cve}" | jq -r '.data[0].epss // "0"'
}

# Heuristic scoring:
#   +70 if in KEV, + (EPSS * 30), +10 if service likely internet-facing (optional, set EXPOSED=1)
EXPOSED="${EXPOSED:-0}"

{
  for cve in "${CVES[@]}"; do
    in_kev=$(jq --arg c "$cve" '[.vulnerabilities[] | select(.cveID==$c)] | length' "$TMP_DIR/kev.json")
    epss=$(get_epss "$cve")
    score=$(awk -v kev="$in_kev" -v epss="$epss" -v exposed="$EXPOSED" \
      'BEGIN{s=0; if(kev>0)s+=70; s+=epss*30; if(exposed>0)s+=10; print s}')
    printf "%s\t%.2f\t%s\t%s\n" "$score" "$epss" "$([ "$in_kev" -gt 0 ] && echo KEV || echo "-")" "$cve"
  done
} | sort -nr -k1,1 | awk 'BEGIN{printf("%-6s %-6s %-5s %s\n","SCORE","EPSS","KEV","CVE")} {printf("%-6s %-6s %-5s %s\n",$1,$2,$3,$4)}'

Run it:

chmod +x get_cves_*.sh prioritize_cves.sh
EXPOSED=1 ./prioritize_cves.sh

You’ll get a ranked list like:

SCORE  EPSS   KEV   CVE
93.40  0.78   KEV   CVE-2024-6387
81.50  0.38   KEV   CVE-2023-XXXX
44.10  0.47   -     CVE-2024-YYYY
...

Interpretation:

  • Patch KEV items first—especially those with high EPSS.

  • Next, sort by score across the fleet. This is your AI-assisted queue.

Real-world note: High-profile issues like OpenSSH “RegreSSHion” (CVE-2024-6387) quickly appear in KEV and trend with high EPSS. This pipeline will push them to the top automatically.


3) Test patches safely in containers before production

Use containers as disposable canaries for basic smoke tests.

Example: test an OpenSSL update on three common bases.

Ubuntu (apt):

podman run --rm -ti ubuntu:22.04 bash -lc '
  apt update && apt install -y openssl && openssl version
  apt upgrade -y openssl && openssl version
'

Fedora (dnf):

podman run --rm -ti fedora:40 bash -lc '
  dnf -y upgrade-minimal openssl && openssl version
'

openSUSE (zypper):

podman run --rm -ti opensuse/leap:15.5 bash -lc '
  zypper refresh && zypper -n patch --with-interactive --auto-agree-with-licenses
  rpm -q openssl && openssl version
'

Add your app’s smoke tests:

#!/usr/bin/env bash
set -euo pipefail
podman run --rm -v "$PWD/tests:/tests:ro" ubuntu:22.04 bash -lc '
  apt update && apt -y upgrade
  /tests/smoke.sh
'

If smoke fails, halt rollout and investigate.


4) Automate rollouts with native tools (canary → waves)

Automate patch application using distro-supported mechanisms, starting with a small “canary” group before the rest.

Debian/Ubuntu: unattended-upgrades

sudo apt install -y unattended-upgrades
sudo bash -c 'cat >/etc/apt/apt.conf.d/20auto-upgrades <<EOF
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
EOF'
# Optional: restrict to security only (default on Ubuntu)
sudo sed -i "s#//\s\?\"\${distro_id}:\${distro_codename}-security\";#\"\${distro_id}:\${distro_codename}-security\";#g" \
  /etc/apt/apt.conf.d/50unattended-upgrades
sudo systemctl restart unattended-upgrades.service || true

Fedora/RHEL/CentOS Stream: dnf-automatic

sudo dnf install -y dnf-automatic
sudo sed -i 's/^apply_updates.*/apply_updates = yes/' /etc/dnf/automatic.conf
sudo systemctl enable --now dnf-automatic.timer

openSUSE/SLES: zypper via systemd timer

sudo bash -c 'cat >/etc/systemd/system/auto-patch.service <<EOF
[Unit]
Description=Automated security patching with zypper
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/bin/zypper -n refresh
ExecStart=/usr/bin/zypper -n patch --with-interactive --auto-agree-with-licenses
# Optional: reboot if needed
# ExecStart=/usr/bin/needs-restarting -r || /usr/bin/systemctl reboot

[Install]
WantedBy=multi-user.target
EOF
cat >/etc/systemd/system/auto-patch.timer <<EOF
[Unit]
Description=Daily security patching

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=timers.target
EOF
systemctl daemon-reload
systemctl enable --now auto-patch.timer'

Rollout strategy:

  • Tag a small set of canary hosts (one per OS/role).

  • Run the timer only on canaries for 24–48 hours.

  • If stable, expand to 25%, then 100%.

  • Use your score list to bump urgent hosts to the front of the queue.


5) Close the loop: learn from failures and drift

Collect patch outcomes and feed them back into your decisions.

Basic logging:

# Recent apt unattended-upgrade logs
sudo journalctl -u unattended-upgrades --since "24 hours ago"

# dnf-automatic
sudo journalctl -u dnf-automatic.timer -u dnf-automatic --since "24 hours ago"

# zypper auto-patch
sudo journalctl -u auto-patch.service --since "24 hours ago"

Aggregate failures (per wave) and auto-adjust:

  • If a patch breaks canaries, drop its score or blacklist temporarily.

  • If an exposed service remains unpatched for >X days, raise urgency.

  • Persist your CVE scores and outcomes (JSON in a Git repo or S3) to track MTTP (mean time to patch).


Putting it all together

  • Inventory and context: know what’s internet-facing.

  • Prioritize with AI signals: KEV + EPSS + severity → a score.

  • Test in containers: fail fast before prod.

  • Automate rollouts with native tools: unattended-upgrades, dnf-automatic, zypper + timer.

  • Learn and adapt: use logs and breakage to refine decisions.

This approach gives you measurable risk reduction without a heavy platform. You can enrich it later with vendor OVAL feeds, CI pipelines, or a central service that merges fleet-wide data.

Call to action: 1) Install the prerequisites and run prioritize_cves.sh on one host. 2) Stand up the container smoke test for your most critical service. 3) Enable automated patching for a canary group this week.

If you want a ready-to-use repo with these scripts and timers, reply and I’ll package them for you.