Hunter Black Hat SEO
Server:LiteSpeed
System:Linux raton.hozzt.com 4.18.0-553.144.1.lve.el8.x86_64 #1 SMP Thu Jul 16 08:31:06 UTC 2026 x86_64
User:altinkayamarble (1260)
PHP:7.4.33
Disabled:symlink, show_source, system, virtual, shell_exec,passthru, exec, popen, proc_open, proc_close, proc_nice, proc_terminate,proc_get_status, pfsockopen,allow_url_fopen, posix_getpwuid, eval,posix_setsid, posix_mkfifo, posix_setpgid,posix_setuid, posix_uname,posix_kill,apache_child_terminate, apache_setenv,define_syslog_variables,escapeshellarg, escapeshellcmd, leak, dl, fp, fput,ftp_connect, ftp_exec,ftp_get, ftp_login, ftp_nb_fput, ftp_put, ftp_raw, ftp_rawlist,highlight_file, ini_alter, ini_get_all, ini_restore, inject_code
Upload Files
File: //opt/cpanel-security.sh
#!/bin/bash
#
# cPanel / WHM Linux Security Audit
# Version: 1.0
#
# PURPOSE:
#   Read-only security audit for cPanel/WHM Linux servers.
#
# IMPORTANT:
#   - No service restarts
#   - No configuration changes
#   - No package installation/update
#   - No firewall changes
#   - No remediation
#   - The only intentional filesystem write is the HTML report.
#

set +e

SCRIPT_VERSION="1.0"
REPORT_DATE="$(date '+%Y-%m-%d')"
REPORT_TIME="$(date '+%Y-%m-%d %H:%M:%S %Z')"
DEFAULT_REPORT="/usr/local/apache/htdocs/cpanel-security-audit-${REPORT_DATE}.html"
REPORT_FILE="${1:-$DEFAULT_REPORT}"

if [ "$(id -u)" -ne 0 ]; then
    echo "[FAIL] This audit must be run as root."
    exit 1
fi

REPORT_DIR="$(dirname "$REPORT_FILE")"

if [ ! -d "$REPORT_DIR" ]; then
    echo "[FAIL] Report directory does not exist: $REPORT_DIR"
    echo "[INFO] No directory will be created by this read-only audit."
    exit 1
fi

if [ ! -w "$REPORT_DIR" ]; then
    echo "[FAIL] Report directory is not writable: $REPORT_DIR"
    exit 1
fi

# ============================================================
# Counters
# ============================================================

PASS_COUNT=0
WARN_COUNT=0
FAIL_COUNT=0
INFO_COUNT=0

# ============================================================
# Helper functions
# ============================================================

html_escape() {
    printf '%s' "$1" |
        sed \
            -e 's/&/\&/g' \
            -e 's/</\&lt;/g' \
            -e 's/>/\&gt;/g' \
            -e 's/"/\&quot;/g' \
            -e "s/'/\&#39;/g"
}

status_class() {
    case "$1" in
        PASS) echo "pass" ;;
        WARN) echo "warn" ;;
        FAIL) echo "fail" ;;
        INFO) echo "info" ;;
        *) echo "info" ;;
    esac
}

print_terminal_status() {
    local status="$1"
    local title="$2"
    local detail="$3"

    printf '[%-4s] %-32s %s\n' "$status" "$title" "$detail"

    case "$status" in
        PASS) PASS_COUNT=$((PASS_COUNT + 1)) ;;
        WARN) WARN_COUNT=$((WARN_COUNT + 1)) ;;
        FAIL) FAIL_COUNT=$((FAIL_COUNT + 1)) ;;
        INFO) INFO_COUNT=$((INFO_COUNT + 1)) ;;
    esac
}

add_result() {
    local title="$1"
    local status="$2"
    local detail="$3"
    local recommendation="$4"
    local class

    class="$(status_class "$status")"

    print_terminal_status "$status" "$title" "$detail"

    cat >> "$REPORT_FILE" <<EOF
<div class="result ${class}">
  <div class="result-head">
    <span class="badge ${class}">$(html_escape "$status")</span>
    <strong>$(html_escape "$title")</strong>
  </div>
  <div class="detail">$(html_escape "$detail")</div>
  <div class="recommendation"><b>Recommendation:</b> $(html_escape "$recommendation")</div>
</div>
EOF
}

section_start() {
    local title="$1"

    echo
    echo "============================================================"
    echo "$title"
    echo "============================================================"

    cat >> "$REPORT_FILE" <<EOF
<section>
<h2>$(html_escape "$title")</h2>
EOF
}

section_end() {
    printf '</section>\n' >> "$REPORT_FILE"
}

add_table_header() {
    cat >> "$REPORT_FILE" <<EOF
<table>
<tr>
EOF
}

add_table_cell() {
    printf '<td>%s</td>\n' "$(html_escape "$1")" >> "$REPORT_FILE"
}

add_table_header_cell() {
    printf '<th>%s</th>\n' "$(html_escape "$1")" >> "$REPORT_FILE"
}

# ============================================================
# HTML Header
# ============================================================

cat > "$REPORT_FILE" <<EOF
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>cPanel Security Audit - $(html_escape "$(hostname -s 2>/dev/null)") - ${REPORT_DATE}</title>
<style>
body {
    font-family: Arial, Helvetica, sans-serif;
    margin: 0;
    padding: 0;
    background: #f4f6f8;
    color: #202124;
}
.container {
    max-width: 1400px;
    margin: auto;
    padding: 24px;
}
header {
    background: #ffffff;
    padding: 24px;
    border-radius: 10px;
    margin-bottom: 20px;
    box-shadow: 0 1px 4px rgba(0,0,0,.08);
}
h1 {
    margin: 0 0 8px 0;
}
h2 {
    margin-top: 0;
    padding-bottom: 10px;
    border-bottom: 2px solid #ddd;
}
h3 {
    margin-top: 24px;
}
section {
    background: #ffffff;
    padding: 20px;
    margin-bottom: 20px;
    border-radius: 10px;
    box-shadow: 0 1px 4px rgba(0,0,0,.06);
}
.summary {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
    margin-top: 18px;
}
.summary-box {
    min-width: 120px;
    padding: 14px;
    border-radius: 8px;
    background: #f1f3f4;
}
.summary-box b {
    display: block;
    font-size: 24px;
    margin-bottom: 4px;
}
.result {
    border-left: 5px solid #777;
    padding: 12px 15px;
    margin: 10px 0;
    background: #fafafa;
    border-radius: 5px;
}
.result.pass { border-left-color: #198754; }
.result.warn { border-left-color: #f0ad00; }
.result.fail { border-left-color: #dc3545; }
.result.info { border-left-color: #0d6efd; }

.result-head {
    display: flex;
    gap: 10px;
    align-items: center;
}
.badge {
    display: inline-block;
    min-width: 48px;
    text-align: center;
    padding: 4px 7px;
    border-radius: 4px;
    color: #fff;
    font-size: 12px;
    font-weight: bold;
}
.badge.pass { background: #198754; }
.badge.warn { background: #f0ad00; }
.badge.fail { background: #dc3545; }
.badge.info { background: #0d6efd; }

.detail {
    margin-top: 8px;
    white-space: pre-wrap;
    word-break: break-word;
}
.recommendation {
    margin-top: 7px;
    color: #555;
}

table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 12px;
    font-size: 14px;
}
th, td {
    border: 1px solid #ddd;
    padding: 8px;
    text-align: left;
    vertical-align: top;
}
th {
    background: #f1f3f4;
}
pre {
    white-space: pre-wrap;
    word-break: break-word;
    background: #f6f8fa;
    padding: 12px;
    border-radius: 6px;
}
footer {
    color: #666;
    text-align: center;
    padding: 20px;
    font-size: 12px;
}
.small {
    color: #666;
    font-size: 13px;
}
</style>
</head>
<body>
<div class="container">

<header>
<h1>cPanel / WHM Linux Security Audit</h1>
<div class="small">Audit Date: $(html_escape "$REPORT_TIME")</div>
<div class="small">Hostname: $(html_escape "$(hostname -f 2>/dev/null)")</div>
<div class="small">Script Version: $(html_escape "$SCRIPT_VERSION")</div>
<div class="small">Mode: Read-only audit; HTML report generation is the only intended filesystem write.</div>

<div class="summary">
<div class="summary-box"><b id="pass-count">0</b>PASS</div>
<div class="summary-box"><b id="warn-count">0</b>WARN</div>
<div class="summary-box"><b id="fail-count">0</b>FAIL</div>
<div class="summary-box"><b id="info-count">0</b>INFO</div>
</div>
</header>
EOF

echo "[INFO] Starting cPanel security audit..."
echo "[INFO] Report: $REPORT_FILE"
echo

# ============================================================
# 1. Server Information
# ============================================================

section_start "1. Server Information"

HOSTNAME_FQDN="$(hostname -f 2>/dev/null)"
OS_NAME="$(grep '^PRETTY_NAME=' /etc/os-release 2>/dev/null | cut -d= -f2- | tr -d '"')"
KERNEL="$(uname -r 2>/dev/null)"
ARCH="$(uname -m 2>/dev/null)"
UPTIME="$(uptime -p 2>/dev/null)"
CPANEL_VERSION="$(cat /usr/local/cpanel/version 2>/dev/null)"

add_table_header
add_table_header_cell "Item"
add_table_header_cell "Value"
printf '</tr>\n' >> "$REPORT_FILE"

for item in \
    "Hostname|$HOSTNAME_FQDN" \
    "Operating System|$OS_NAME" \
    "Kernel|$KERNEL" \
    "Architecture|$ARCH" \
    "Uptime|$UPTIME" \
    "cPanel Version|$CPANEL_VERSION"
do
    IFS='|' read -r key value <<< "$item"
    printf '<tr>' >> "$REPORT_FILE"
    add_table_cell "$key"
    add_table_cell "$value"
    printf '</tr>\n' >> "$REPORT_FILE"
done

printf '</table>\n' >> "$REPORT_FILE"

section_end

# ============================================================
# 2. SSH Security
# ============================================================

section_start "2. SSH Security"

SSH_PORT=""
PERMIT_ROOT=""
PASSWORD_AUTH=""
PUBKEY_AUTH=""

if command -v sshd >/dev/null 2>&1; then
    SSHD_T="$(sshd -T 2>/dev/null)"

    SSH_PORT="$(printf '%s\n' "$SSHD_T" | awk '$1=="port"{print $2; exit}')"
    PERMIT_ROOT="$(printf '%s\n' "$SSHD_T" | awk '$1=="permitrootlogin"{print $2; exit}')"
    PASSWORD_AUTH="$(printf '%s\n' "$SSHD_T" | awk '$1=="passwordauthentication"{print $2; exit}')"
    PUBKEY_AUTH="$(printf '%s\n' "$SSHD_T" | awk '$1=="pubkeyauthentication"{print $2; exit}')"
fi

if [ -z "$SSH_PORT" ]; then
    SSH_PORT="$(grep -Ei '^[[:space:]]*Port[[:space:]]+' /etc/ssh/sshd_config 2>/dev/null |
        tail -1 | awk '{print $2}')"
fi

if [ -z "$PERMIT_ROOT" ]; then
    PERMIT_ROOT="$(grep -Ei '^[[:space:]]*PermitRootLogin[[:space:]]+' /etc/ssh/sshd_config 2>/dev/null |
        tail -1 | awk '{print tolower($2)}')"
fi

if [ -z "$PASSWORD_AUTH" ]; then
    PASSWORD_AUTH="$(grep -Ei '^[[:space:]]*PasswordAuthentication[[:space:]]+' /etc/ssh/sshd_config 2>/dev/null |
        tail -1 | awk '{print tolower($2)}')"
fi

if [ -z "$PUBKEY_AUTH" ]; then
    PUBKEY_AUTH="$(grep -Ei '^[[:space:]]*PubkeyAuthentication[[:space:]]+' /etc/ssh/sshd_config 2>/dev/null |
        tail -1 | awk '{print tolower($2)}')"
fi

if [ "$PERMIT_ROOT" = "no" ]; then
    add_result "Direct Root SSH Authentication" "PASS" \
        "PermitRootLogin is disabled." \
        "Keep direct root SSH login disabled and use controlled administrative accounts."
elif [ -n "$PERMIT_ROOT" ]; then
    add_result "Direct Root SSH Authentication" "WARN" \
        "PermitRootLogin is set to $PERMIT_ROOT." \
        "Disable direct root SSH login where operationally possible."
else
    add_result "Direct Root SSH Authentication" "INFO" \
        "Unable to determine PermitRootLogin." \
        "Review the effective SSH configuration."
fi

if [ "$PUBKEY_AUTH" = "yes" ]; then
    add_result "SSH Key Authentication" "INFO" \
        "SSH public-key authentication is enabled." \
        "Review authorized keys and remove unused keys."
elif [ "$PUBKEY_AUTH" = "no" ]; then
    add_result "SSH Key Authentication" "WARN" \
        "SSH public-key authentication is disabled." \
        "Consider using SSH keys for administrative access."
else
    add_result "SSH Key Authentication" "INFO" \
        "Unable to determine SSH public-key authentication state." \
        "Review the effective SSH configuration."
fi

if [ "$PASSWORD_AUTH" = "no" ]; then
    add_result "SSH Password Authentication" "PASS" \
        "SSH password authentication is disabled." \
        "Continue using key-based authentication where practical."
elif [ "$PASSWORD_AUTH" = "yes" ]; then
    add_result "SSH Password Authentication" "WARN" \
        "SSH password authentication is enabled." \
        "Consider disabling SSH password authentication after validating key-based access."
else
    add_result "SSH Password Authentication" "INFO" \
        "Unable to determine SSH password authentication state." \
        "Review the effective SSH configuration."
fi

if [ "$SSH_PORT" = "22" ]; then
    add_result "SSH Port" "WARN" \
        "SSH is listening on the default port 22." \
        "Consider using an alternate SSH port as part of the server hardening baseline."
elif [ -n "$SSH_PORT" ]; then
    add_result "SSH Port" "PASS" \
        "SSH configured port: $SSH_PORT." \
        "Keep the SSH port documented and restricted to trusted sources where possible."
else
    add_result "SSH Port" "INFO" \
        "Unable to determine SSH port." \
        "Review the effective SSH configuration."
fi

section_end

# ============================================================
# 3. PHP Security
# ============================================================

section_start "3. PHP Security"

PHP_FOUND=0

for PHP_BIN in /opt/cpanel/ea-php*/root/usr/bin/php; do
    [ -x "$PHP_BIN" ] || continue

    PHP_FOUND=1
    PHP_VERSION="$("$PHP_BIN" -r 'echo PHP_VERSION;' 2>/dev/null)"
    PHP_INI="$("$PHP_BIN" --ini 2>/dev/null | awk -F': ' '/Loaded Configuration File/{print $2}')"

    DISABLE_FUNCTIONS="$("$PHP_BIN" -r 'echo ini_get("disable_functions");' 2>/dev/null)"
    ALLOW_URL_INCLUDE="$("$PHP_BIN" -r 'echo ini_get("allow_url_include");' 2>/dev/null)"
    EXPOSE_PHP="$("$PHP_BIN" -r 'echo ini_get("expose_php");' 2>/dev/null)"

    if [ -n "$DISABLE_FUNCTIONS" ]; then
        add_result "PHP $PHP_VERSION - disable_functions" "PASS" \
            "disable_functions is configured: $DISABLE_FUNCTIONS" \
            "Review the list periodically and ensure dangerous functions are restricted according to the hosting security baseline."
    else
        add_result "PHP $PHP_VERSION - disable_functions" "WARN" \
            "disable_functions is empty." \
            "Review whether dangerous PHP functions should be disabled for this hosting environment."
    fi

    if [ "$ALLOW_URL_INCLUDE" = "0" ] || [ "$ALLOW_URL_INCLUDE" = "Off" ]; then
        add_result "PHP $PHP_VERSION - allow_url_include" "PASS" \
            "allow_url_include is disabled." \
            "Keep allow_url_include disabled unless a documented application requirement exists."
    else
        add_result "PHP $PHP_VERSION - allow_url_include" "WARN" \
            "allow_url_include is $ALLOW_URL_INCLUDE." \
            "Disable allow_url_include unless specifically required."
    fi

    if [ "$EXPOSE_PHP" = "0" ] || [ "$EXPOSE_PHP" = "Off" ]; then
        add_result "PHP $PHP_VERSION - expose_php" "PASS" \
            "expose_php is disabled." \
            "Keep PHP version exposure disabled."
    else
        add_result "PHP $PHP_VERSION - expose_php" "WARN" \
            "expose_php is $EXPOSE_PHP." \
            "Disable expose_php to reduce unnecessary version disclosure."
    fi

    cat >> "$REPORT_FILE" <<EOF
<div class="small">PHP binary: $(html_escape "$PHP_BIN") | Loaded php.ini: $(html_escape "$PHP_INI")</div>
EOF
done

if [ "$PHP_FOUND" -eq 0 ]; then
    add_result "EA-PHP Versions" "INFO" \
        "No EasyApache PHP binaries were detected under /opt/cpanel." \
        "Verify PHP installation manually if PHP is expected on this server."
fi

section_end

# ============================================================
# 4. cPHulk
# ============================================================

section_start "4. cPHulk"

CPHULK_STATUS=""

if command -v whmapi1 >/dev/null 2>&1; then
    CPHULK_RAW="$(whmapi1 --output=json cphulk_status 2>/dev/null)"
    CPHULK_STATUS="$(printf '%s\n' "$CPHULK_RAW" |
        grep -oE '"is_enabled"[[:space:]]*:[[:space:]]*(0|1|true|false)' |
        head -1 |
        sed -E 's/.*:[[:space:]]*//')"
fi

case "$CPHULK_STATUS" in
    1|true)
        add_result "cPHulk" "PASS" \
            "cPHulk appears to be enabled." \
            "Keep cPHulk enabled and review its protection settings."
        ;;
    0|false)
        add_result "cPHulk" "WARN" \
            "cPHulk appears to be disabled." \
            "Enable cPHulk after validating compatibility with the server's access requirements."
        ;;
    *)
        add_result "cPHulk" "INFO" \
            "Unable to determine cPHulk state from the available WHM API output." \
            "Verify cPHulk status in WHM."
        ;;
esac

section_end

# ============================================================
# 5. Shell Fork Bomb Protection
# ============================================================

section_start "5. Shell Fork Bomb Protection"

FORK_LIMIT_PROFILE=""

if [ -d /var/cpanel/login_profile/limits ] ||
   [ -f /var/cpanel/login_profile/limits ] ||
   [ -d /usr/local/cpanel/etc/login_profile/limits ] ||
   [ -f /usr/local/cpanel/etc/login_profile/limits ]; then

    FORK_LIMIT_PROFILE="present"
fi

if [ "$FORK_LIMIT_PROFILE" = "present" ]; then
    add_result "Shell Fork Bomb Protection" "PASS" \
        "cPanel login profile limits configuration was detected." \
        "Keep the cPanel shell limits profile enabled and periodically verify its configuration."
else
    add_result "Shell Fork Bomb Protection" "WARN" \
        "The cPanel login profile limits configuration was not detected in the expected locations." \
        "Verify the Shell Fork Bomb Protection / limits login profile in cPanel."
fi

section_end

# ============================================================
# 6. SMTP Security
# ============================================================

section_start "6. SMTP Security"

SMTP_RESTRICTION=""

if [ -f /var/cpanel/cpanel.config ]; then
    SMTP_RESTRICTION="$(grep -Ei '^smtpmailgidonly=' /var/cpanel/cpanel.config 2>/dev/null |
        tail -1 | cut -d= -f2)"
fi

if [ "$SMTP_RESTRICTION" = "1" ]; then
    add_result "SMTP Restrictions" "PASS" \
        "SMTP mail gid restriction is enabled." \
        "Keep SMTP restrictions enabled to limit direct outbound SMTP abuse."
elif [ "$SMTP_RESTRICTION" = "0" ]; then
    add_result "SMTP Restrictions" "WARN" \
        "SMTP mail gid restriction is disabled." \
        "Review the SMTP restriction setting in WHM."
else
    add_result "SMTP Restrictions" "INFO" \
        "Unable to determine the SMTP restriction setting." \
        "Review SMTP Restrictions in WHM."
fi

section_end

# ============================================================
# 7. WHM Password Security
# ============================================================

section_start "7. WHM Password Security"

MIN_PW_STRENGTH=""

if [ -f /var/cpanel/cpanel.config ]; then
    MIN_PW_STRENGTH="$(grep -Ei '^minpwstrength=' /var/cpanel/cpanel.config 2>/dev/null |
        tail -1 | cut -d= -f2)"
fi

if [[ "$MIN_PW_STRENGTH" =~ ^[0-9]+$ ]]; then
    if [ "$MIN_PW_STRENGTH" -ge 50 ]; then
        add_result "Minimum Password Strength" "PASS" \
            "Configured minimum password strength: $MIN_PW_STRENGTH." \
            "Maintain a strong password-strength baseline and review it periodically."
    else
        add_result "Minimum Password Strength" "WARN" \
            "Configured minimum password strength: $MIN_PW_STRENGTH." \
            "Consider increasing the minimum password-strength requirement."
    fi
else
    add_result "Minimum Password Strength" "INFO" \
        "Unable to determine minimum password strength." \
        "Review Password Strength Configuration in WHM."
fi

section_end

# ============================================================
# 8. Compiler Access
# ============================================================

section_start "8. Compiler Security"

GCC_PATH="/usr/bin/gcc"

if [ -e "$GCC_PATH" ]; then
    GCC_OWNER="$(stat -c '%U:%G' "$GCC_PATH" 2>/dev/null)"
    GCC_MODE="$(stat -c '%a' "$GCC_PATH" 2>/dev/null)"

    if [ "$GCC_OWNER" = "root:compiler" ] && [ "$GCC_MODE" = "750" ]; then
        add_result "Compiler Access" "PASS" \
            "gcc ownership/mode is $GCC_OWNER $GCC_MODE." \
            "Keep compiler access restricted to authorized users/groups."
    else
        add_result "Compiler Access" "WARN" \
            "gcc exists with ownership/mode $GCC_OWNER $GCC_MODE." \
            "Review compiler access against the organization's shared-hosting security baseline."
    fi
else
    add_result "Compiler Access" "PASS" \
        "gcc was not found at /usr/bin/gcc." \
        "No compiler was detected at the standard path."
fi

section_end

# ============================================================
# 9. /tmp Security
# ============================================================

section_start "9. /tmp Security"

if [ -e /var/cpanel/disabled/securetmp ]; then
    add_result "Secure /tmp" "WARN" \
        "The cPanel securetmp disabled marker was detected." \
        "Verify the securetmp configuration and mount protection in WHM."
else
    TMP_MOUNT="$(mount 2>/dev/null | grep -E ' on /tmp( |$)')"
    VARTMP_MOUNT="$(mount 2>/dev/null | grep -E ' on /var/tmp( |$)')"

    if printf '%s\n' "$TMP_MOUNT" | grep -q '/usr/tmpDSK' &&
       printf '%s\n' "$VARTMP_MOUNT" | grep -q '/usr/tmpDSK'; then

        add_result "Secure /tmp" "PASS" \
            "Both /tmp and /var/tmp appear to use the cPanel tmp disk mount." \
            "Keep temporary directories protected with appropriate mount options."
    else
        add_result "Secure /tmp" "INFO" \
            "Securetmp marker is absent, but expected tmpDSK mounts were not both detected." \
            "Review /tmp and /var/tmp mounts and their security options."
    fi
fi

section_end

# ============================================================
# 10. ModSecurity
# ============================================================

section_start "10. ModSecurity"

MODSECURITY_MODULE=""

if command -v httpd >/dev/null 2>&1; then
    MODSECURITY_MODULE="$(httpd -M 2>/dev/null | grep -i 'security2_module')"
fi

if [ -n "$MODSECURITY_MODULE" ]; then
    add_result "ModSecurity" "PASS" \
        "Apache security2_module is loaded." \
        "Keep ModSecurity enabled and maintain current rules."
else
    add_result "ModSecurity" "WARN" \
        "Apache security2_module was not detected." \
        "Review ModSecurity configuration in WHM."
fi

section_end

# ============================================================
# 11. Imunify Security
# ============================================================

section_start "11. Imunify Security"

IMUNIFY_FOUND=0

if command -v imunify-antivirus >/dev/null 2>&1; then
    IMUNIFY_FOUND=1

    ACTIVE_SERVICE=""
    for service in imunify-antivirus imunify-antivirus.service; do
        if systemctl is-active --quiet "$service" 2>/dev/null; then
            ACTIVE_SERVICE="$service"
            break
        fi
    done

    if [ -n "$ACTIVE_SERVICE" ]; then
        add_result "ImunifyAV" "PASS" \
            "ImunifyAV is installed and its service appears active ($ACTIVE_SERVICE)." \
            "Keep malware protection active and review malware detections regularly."
    else
        add_result "ImunifyAV" "WARN" \
            "ImunifyAV is installed, but an active service was not detected." \
            "Verify the ImunifyAV service status."
    fi

    MALWARE_OUTPUT="$(imunify-antivirus malware malicious list --limit 100 2>/dev/null)"
    INFECTED_OUTPUT="$(imunify-antivirus malware infected-domains --limit 100 2>/dev/null)"

    MALWARE_DATA="$(printf '%s\n' "$MALWARE_OUTPUT" |
        grep -vE '^[[:space:]]*$|^[[:space:]]*(ID|ID[[:space:]]+|No data|Nothing|Total|Showing|Malicious|Domain|Error|Usage)' |
        grep -vE '^[[:space:]]*-+[[:space:]]*$' |
        head -20)"

    INFECTED_DATA="$(printf '%s\n' "$INFECTED_OUTPUT" |
        grep -vE '^[[:space:]]*$|^[[:space:]]*(ID|ID[[:space:]]+|No data|Nothing|Total|Showing|Infected|Domain|Error|Usage)' |
        grep -vE '^[[:space:]]*-+[[:space:]]*$' |
        head -20)"

    if [ -n "$MALWARE_DATA" ]; then
        add_result "ImunifyAV Malware Results" "WARN" \
            "The ImunifyAV CLI returned data that may contain malware detections. Review the detailed CLI output below." \
            "Investigate each detection and follow the approved malware-remediation process."
        printf '<h3>ImunifyAV Malware CLI Output</h3><pre>%s</pre>\n' \
            "$(html_escape "$MALWARE_OUTPUT")" >> "$REPORT_FILE"
    else
        add_result "ImunifyAV Malware Results" "PASS" \
            "No malware result rows were detected in the CLI output." \
            "Continue monitoring ImunifyAV malware detections."
    fi

    if [ -n "$INFECTED_DATA" ]; then
        add_result "ImunifyAV Infected Domains" "WARN" \
            "The ImunifyAV CLI returned infected-domain data. Review the detailed output below." \
            "Investigate affected domains using the approved malware-remediation process."
        printf '<h3>ImunifyAV Infected Domains CLI Output</h3><pre>%s</pre>\n' \
            "$(html_escape "$INFECTED_OUTPUT")" >> "$REPORT_FILE"
    else
        add_result "ImunifyAV Infected Domains" "PASS" \
            "No infected-domain result rows were detected in the CLI output." \
            "Continue monitoring infected-domain results."
    fi
fi

if command -v imunify360-agent >/dev/null 2>&1; then
    IMUNIFY_FOUND=1

    ACTIVE_SERVICE=""
    for service in imunify-antivirus imunify360 imunify360-agent imunify360-agent.service; do
        if systemctl is-active --quiet "$service" 2>/dev/null; then
            ACTIVE_SERVICE="$service"
            break
        fi
    done

    if [ -n "$ACTIVE_SERVICE" ]; then
        add_result "Imunify360" "PASS" \
            "Imunify360 is installed and an active service was detected ($ACTIVE_SERVICE)." \
            "Keep Imunify360 active and review malware detections regularly."
    else
        add_result "Imunify360" "WARN" \
            "Imunify360 is installed, but an active service was not detected." \
            "Verify the Imunify360 service status."
    fi

    MALWARE_OUTPUT="$(imunify360-agent malware malicious list --limit 100 2>/dev/null)"
    INFECTED_OUTPUT="$(imunify360-agent malware infected-domains --limit 100 2>/dev/null)"

    MALWARE_DATA="$(printf '%s\n' "$MALWARE_OUTPUT" |
        grep -vE '^[[:space:]]*$|^[[:space:]]*(ID|ID[[:space:]]+|No data|Nothing|Total|Showing|Malicious|Domain|Error|Usage)' |
        grep -vE '^[[:space:]]*-+[[:space:]]*$' |
        head -20)"

    INFECTED_DATA="$(printf '%s\n' "$INFECTED_OUTPUT" |
        grep -vE '^[[:space:]]*$|^[[:space:]]*(ID|ID[[:space:]]+|No data|Nothing|Total|Showing|Infected|Domain|Error|Usage)' |
        grep -vE '^[[:space:]]*-+[[:space:]]*$' |
        head -20)"

    if [ -n "$MALWARE_DATA" ]; then
        add_result "Imunify360 Malware Results" "WARN" \
            "The Imunify360 CLI returned data that may contain malware detections. Review the detailed CLI output below." \
            "Investigate each detection and follow the approved malware-remediation process."
        printf '<h3>Imunify360 Malware CLI Output</h3><pre>%s</pre>\n' \
            "$(html_escape "$MALWARE_OUTPUT")" >> "$REPORT_FILE"
    else
        add_result "Imunify360 Malware Results" "PASS" \
            "No malware result rows were detected in the CLI output." \
            "Continue monitoring Imunify360 malware detections."
    fi

    if [ -n "$INFECTED_DATA" ]; then
        add_result "Imunify360 Infected Domains" "WARN" \
            "The Imunify360 CLI returned infected-domain data. Review the detailed output below." \
            "Investigate affected domains using the approved malware-remediation process."
        printf '<h3>Imunify360 Infected Domains CLI Output</h3><pre>%s</pre>\n' \
            "$(html_escape "$INFECTED_OUTPUT")" >> "$REPORT_FILE"
    else
        add_result "Imunify360 Infected Domains" "PASS" \
            "No infected-domain result rows were detected in the CLI output." \
            "Continue monitoring infected-domain results."
    fi
fi

if [ "$IMUNIFY_FOUND" -eq 0 ]; then
    add_result "Imunify Security" "INFO" \
        "Neither ImunifyAV nor Imunify360 CLI was detected." \
        "Verify whether malware protection is provided by another approved security product."
fi

section_end

# ============================================================
# 12. PHP-FPM
# ============================================================

section_start "12. PHP-FPM"

PHPFPM_FOUND=0

for FPM_BIN in /opt/cpanel/ea-php*/root/usr/sbin/php-fpm*; do
    [ -x "$FPM_BIN" ] || continue
    PHPFPM_FOUND=1
    break
done

if [ "$PHPFPM_FOUND" -eq 1 ]; then
    add_result "PHP-FPM" "PASS" \
        "EasyApache PHP-FPM binaries were detected." \
        "Keep PHP-FPM versions maintained and review pool resource limits."
else
    add_result "PHP-FPM" "INFO" \
        "EasyApache PHP-FPM binaries were not detected." \
        "Verify PHP-FPM requirements for hosted applications."
fi

section_end

# ============================================================
# 13. Apache Security
# ============================================================

section_start "13. Apache Security"

HTTPD_CONF_DIR=""

if [ -d /etc/apache2 ]; then
    HTTPD_CONF_DIR="/etc/apache2"
elif [ -d /etc/httpd ]; then
    HTTPD_CONF_DIR="/etc/httpd"
fi

SERVER_TOKENS=""
SERVER_SIGNATURE=""
TRACE_ENABLE=""

if [ -n "$HTTPD_CONF_DIR" ]; then
    SERVER_TOKENS="$(grep -RHiE '^[[:space:]]*ServerTokens[[:space:]]+' "$HTTPD_CONF_DIR" 2>/dev/null |
        tail -1 | awk '{print $2}')"

    SERVER_SIGNATURE="$(grep -RHiE '^[[:space:]]*ServerSignature[[:space:]]+' "$HTTPD_CONF_DIR" 2>/dev/null |
        tail -1 | awk '{print $2}')"

    TRACE_ENABLE="$(grep -RHiE '^[[:space:]]*TraceEnable[[:space:]]+' "$HTTPD_CONF_DIR" 2>/dev/null |
        tail -1 | awk '{print $2}')"
fi

case "$(echo "$SERVER_TOKENS" | tr '[:upper:]' '[:lower:]')" in
    prod)
        add_result "Apache ServerTokens" "PASS" \
            "ServerTokens is configured as Prod." \
            "Keep Apache version/product disclosure minimized."
        ;;
    "")
        add_result "Apache ServerTokens" "INFO" \
            "No explicit ServerTokens directive was detected." \
            "Review the effective Apache configuration and consider a minimal disclosure setting."
        ;;
    *)
        add_result "Apache ServerTokens" "WARN" \
            "ServerTokens is configured as $SERVER_TOKENS." \
            "Consider using ServerTokens Prod for reduced information disclosure."
        ;;
esac

case "$(echo "$SERVER_SIGNATURE" | tr '[:upper:]' '[:lower:]')" in
    off)
        add_result "Apache ServerSignature" "PASS" \
            "ServerSignature is disabled." \
            "Keep ServerSignature disabled."
        ;;
    "")
        add_result "Apache ServerSignature" "INFO" \
            "No explicit ServerSignature directive was detected." \
            "Review the effective Apache configuration."
        ;;
    *)
        add_result "Apache ServerSignature" "WARN" \
            "ServerSignature is configured as $SERVER_SIGNATURE." \
            "Disable ServerSignature."
        ;;
esac

case "$(echo "$TRACE_ENABLE" | tr '[:upper:]' '[:lower:]')" in
    off)
        add_result "Apache TraceEnable" "PASS" \
            "TraceEnable is disabled." \
            "Keep HTTP TRACE disabled unless specifically required."
        ;;
    "")
        add_result "Apache TraceEnable" "INFO" \
            "No explicit TraceEnable directive was detected." \
            "Review the effective Apache configuration."
        ;;
    *)
        add_result "Apache TraceEnable" "WARN" \
            "TraceEnable is configured as $TRACE_ENABLE." \
            "Disable HTTP TRACE unless specifically required."
        ;;
esac

HEADERS_MODULE=""

if command -v httpd >/dev/null 2>&1; then
    HEADERS_MODULE="$(httpd -M 2>/dev/null | grep -i 'headers_module')"
fi

if [ -n "$HEADERS_MODULE" ]; then
    add_result "Apache mod_headers" "PASS" \
        "headers_module is loaded." \
        "Keep required security headers managed through the approved Apache configuration."
else
    add_result "Apache mod_headers" "INFO" \
        "headers_module was not detected." \
        "Verify whether mod_headers is required for the site's security-header baseline."
fi

section_end

# ============================================================
# 14. CSF
# ============================================================

section_start "14. CSF"

CSF_INSTALLED=0
CSF_RUNNING=0
LFD_RUNNING=0

if [ -x /usr/sbin/csf ] || [ -x /usr/local/cpanel/whostmgr/docroot/cgi/configserver/csf.cgi ]; then
    CSF_INSTALLED=1
fi

if command -v csf >/dev/null 2>&1; then
    CSF_INSTALLED=1
fi

if systemctl is-active --quiet lfd 2>/dev/null ||
   systemctl is-active --quiet lfd.service 2>/dev/null; then
    LFD_RUNNING=1
fi

if command -v csf >/dev/null 2>&1; then
    if csf -l >/dev/null 2>&1; then
        CSF_RUNNING=1
    fi
fi

if [ "$CSF_INSTALLED" -eq 1 ]; then
    if [ "$CSF_RUNNING" -eq 1 ] || [ "$LFD_RUNNING" -eq 1 ]; then
        add_result "CSF Firewall" "PASS" \
            "CSF/LFD installation was detected and firewall/daemon activity appears present." \
            "Keep CSF/LFD maintained and review firewall rules periodically."
    else
        add_result "CSF Firewall" "WARN" \
            "CSF is installed but active firewall/daemon status was not confirmed." \
            "Verify CSF/LFD service status in the server."
    fi
else
    add_result "CSF Firewall" "INFO" \
        "CSF was not detected." \
        "Verify which approved firewall provider protects the server."
fi

section_end

# ============================================================
# 15. Firewall Provider
# ============================================================

section_start "15. Firewall Provider"

FIREWALL_PROVIDER=""

if [ "$CSF_INSTALLED" -eq 1 ]; then
    FIREWALL_PROVIDER="CSF"
fi

if systemctl is-active --quiet firewalld 2>/dev/null; then
    if [ -n "$FIREWALL_PROVIDER" ]; then
        FIREWALL_PROVIDER="$FIREWALL_PROVIDER + firewalld"
    else
        FIREWALL_PROVIDER="firewalld"
    fi
fi

if command -v nft >/dev/null 2>&1; then
    if nft list ruleset >/dev/null 2>&1; then
        if [ -n "$FIREWALL_PROVIDER" ]; then
            FIREWALL_PROVIDER="$FIREWALL_PROVIDER + nftables"
        else
            FIREWALL_PROVIDER="nftables"
        fi
    fi
fi

if command -v iptables >/dev/null 2>&1; then
    if iptables -L -n >/dev/null 2>&1; then
        if [ -n "$FIREWALL_PROVIDER" ]; then
            FIREWALL_PROVIDER="$FIREWALL_PROVIDER + iptables"
        else
            FIREWALL_PROVIDER="iptables"
        fi
    fi
fi

if [ -n "$FIREWALL_PROVIDER" ]; then
    add_result "Firewall Provider" "INFO" \
        "Detected firewall components: $FIREWALL_PROVIDER." \
        "Document the authoritative firewall provider and avoid overlapping firewall management."
else
    add_result "Firewall Provider" "WARN" \
        "No active firewall provider could be confirmed." \
        "Verify the server firewall configuration."
fi

section_end

# ============================================================
# 16. Kernel Review
# ============================================================

section_start "16. Kernel Review"

RUNNING_KERNEL="$(uname -r 2>/dev/null)"
INSTALLED_KERNELS=""

if command -v rpm >/dev/null 2>&1; then
    INSTALLED_KERNELS="$(rpm -q kernel 2>/dev/null | sort -V)"
fi

if [ -n "$INSTALLED_KERNELS" ]; then
    LATEST_KERNEL_PACKAGE="$(printf '%s\n' "$INSTALLED_KERNELS" | tail -1)"
    LATEST_KERNEL_VERSION="$(printf '%s\n' "$LATEST_KERNEL_PACKAGE" |
        sed 's/^kernel-//')"

    if printf '%s\n' "$INSTALLED_KERNELS" | grep -Fq "$RUNNING_KERNEL"; then
        add_result "Kernel Packages" "INFO" \
            "Installed kernel package(s) were detected. Running kernel: $RUNNING_KERNEL. Latest installed package: $LATEST_KERNEL_PACKAGE." \
            "Review installed kernels and reboot when an approved newer kernel is installed and scheduled."
    else
        add_result "Kernel Packages" "WARN" \
            "The running kernel ($RUNNING_KERNEL) was not directly matched to the installed kernel package list." \
            "Review installed kernels and reboot into the approved current kernel when appropriate."
    fi

    printf '<h3>Installed Kernel Packages</h3><pre>%s</pre>\n' \
        "$(html_escape "$INSTALLED_KERNELS")" >> "$REPORT_FILE"
else
    add_result "Kernel Packages" "INFO" \
        "Unable to retrieve installed kernel packages with rpm." \
        "Review installed kernel packages manually."
fi

section_end

# ============================================================
# 17. Privileged & Shell Access Review
# ============================================================

section_start "17. Privileged & Shell Access Review"

ROOT_UID_USERS="$(awk -F: '$3 == 0 {print $1}' /etc/passwd 2>/dev/null)"

if [ -n "$ROOT_UID_USERS" ]; then
    add_result "UID 0 Accounts" "INFO" \
        "UID 0 accounts: $ROOT_UID_USERS" \
        "Ensure every UID 0 account is authorized and required."
else
    add_result "UID 0 Accounts" "WARN" \
        "Unable to determine UID 0 accounts." \
        "Review /etc/passwd manually."
fi

WHEEL_USERS=""

if getent group wheel >/dev/null 2>&1; then
    WHEEL_USERS="$(getent group wheel | awk -F: '{print $4}')"
fi

if [ -n "$WHEEL_USERS" ]; then
    add_result "Wheel Group Users" "WARN" \
        "wheel members: $WHEEL_USERS" \
        "Review all wheel users and remove unnecessary privileged access."
else
    add_result "Wheel Group Users" "PASS" \
        "No wheel group members were detected." \
        "No action required."
fi

SHELL_USERS=""

while IFS=: read -r USERNAME PASSWORD UID GID GECOS HOME SHELL; do
    [ -n "$USERNAME" ] || continue

    case "$SHELL" in
        /sbin/nologin|/usr/sbin/nologin|/bin/false|/usr/bin/false|nologin|false|"")
            continue
            ;;
    esac

    if [ -f /etc/shells ]; then
        if ! grep -Fxq "$SHELL" /etc/shells 2>/dev/null; then
            continue
        fi
    fi

    SHELL_USERS="${SHELL_USERS}${USERNAME}|${UID}|${HOME}|${SHELL}
"
done < /etc/passwd

if [ -n "$SHELL_USERS" ]; then
    SHELL_USER_COUNT="$(printf '%s\n' "$SHELL_USERS" | grep -c '|' 2>/dev/null)"

    add_result "Users With Shell Access" "WARN" \
        "$SHELL_USER_COUNT local user(s) have an interactive shell." \
        "Review every shell-enabled account and disable shell access where it is not required."
else
    add_result "Users With Shell Access" "PASS" \
        "No local users with interactive shell access were detected." \
        "No action required."
fi

printf '<h3>Detailed Shell Access Review</h3>\n' >> "$REPORT_FILE"
add_table_header
add_table_header_cell "Username"
add_table_header_cell "UID"
add_table_header_cell "Home Directory"
add_table_header_cell "Shell"
add_table_header_cell "Shell Access"
add_table_header_cell "cPanel Account"
add_table_header_cell "Wheel"
add_table_header_cell "UID 0"
printf '</tr>\n' >> "$REPORT_FILE"

# Build a cPanel account lookup from /etc/userdomains.
CPANEL_USERS_FILE="/etc/userdomains"

is_cpanel_account() {
    local user="$1"

    if [ -f "$CPANEL_USERS_FILE" ]; then
        if grep -Eq "^[^:]+:[[:space:]]*$user$" "$CPANEL_USERS_FILE" 2>/dev/null; then
            echo "YES"
            return
        fi
    fi

    echo "NO"
}

is_wheel_user() {
    local user="$1"

    if getent group wheel 2>/dev/null |
       awk -F: -v u="$user" '
       {
           n=split($4,a,",")
           for(i=1;i<=n;i++)
               if(a[i]==u)
                   found=1
       }
       END {
           if(found) print "YES"
           else print "NO"
       }'; then
        return
    fi

    echo "NO"
}

while IFS='|' read -r USERNAME UID HOME SHELL; do
    [ -n "$USERNAME" ] || continue

    CPANEL_ACCOUNT="$(is_cpanel_account "$USERNAME")"
    WHEEL="$(is_wheel_user "$USERNAME")"

    if [ "$UID" = "0" ]; then
        UID_ZERO="YES"
    else
        UID_ZERO="NO"
    fi

    printf '<tr>' >> "$REPORT_FILE"
    add_table_cell "$USERNAME"
    add_table_cell "$UID"
    add_table_cell "$HOME"
    add_table_cell "$SHELL"
    add_table_cell "YES"
    add_table_cell "$CPANEL_ACCOUNT"
    add_table_cell "$WHEEL"
    add_table_cell "$UID_ZERO"
    printf '</tr>\n' >> "$REPORT_FILE"

done <<EOF
$SHELL_USERS
EOF

printf '</table>\n' >> "$REPORT_FILE"

NO_SHELL_COUNT=0

while IFS=: read -r USERNAME PASSWORD UID GID GECOS HOME SHELL; do
    [ -n "$USERNAME" ] || continue

    case "$SHELL" in
        /sbin/nologin|/usr/sbin/nologin|/bin/false|/usr/bin/false)
            NO_SHELL_COUNT=$((NO_SHELL_COUNT + 1))
            ;;
    esac
done < /etc/passwd

add_result "Users Without Interactive Shell" "INFO" \
    "$NO_SHELL_COUNT local account(s) use nologin/false shells." \
    "Periodically review service and system accounts."

section_end

# ============================================================
# 18. Network Exposure
# ============================================================

section_start "18. Network Exposure"

NETSTAT_OUTPUT=""

if command -v netstat >/dev/null 2>&1; then
    NETSTAT_OUTPUT="$(netstat -ntlp 2>/dev/null)"
elif command -v ss >/dev/null 2>&1; then
    NETSTAT_OUTPUT="$(ss -ntlp 2>/dev/null)"
fi

if [ -n "$NETSTAT_OUTPUT" ]; then
    add_result "Listening TCP Services" "INFO" \
        "Listening TCP sockets were collected for review." \
        "Review every externally reachable service and close unnecessary listeners."

    printf '<h3>Listening TCP Services</h3><pre>%s</pre>\n' \
        "$(html_escape "$NETSTAT_OUTPUT")" >> "$REPORT_FILE"
else
    add_result "Listening TCP Services" "INFO" \
        "Unable to collect listening TCP sockets." \
        "Review listening services manually with ss or netstat."
fi

section_end

# ============================================================
# 19. Service Review
# ============================================================

section_start "19. Service Review"

check_service() {
    local title="$1"
    shift

    local found=""
    local service
    local state

    for service in "$@"; do
        if systemctl list-unit-files 2>/dev/null |
           awk '{print $1}' |
           grep -Fxq "$service" 2>/dev/null; then
            found="$service"
            break
        fi
    done

    if [ -n "$found" ]; then
        state="$(systemctl is-active "$found" 2>/dev/null)"

        if [ "$state" = "active" ]; then
            add_result "$title" "PASS" \
                "$found is active." \
                "Continue monitoring the service and keep it maintained."
        elif [ "$state" = "inactive" ] || [ "$state" = "failed" ]; then
            add_result "$title" "WARN" \
                "$found is $state." \
                "Confirm whether the service is expected to be running."
        else
            add_result "$title" "INFO" \
                "$found state: $state." \
                "Review the service status if required."
        fi
    else
        add_result "$title" "INFO" \
            "No matching systemd service was detected." \
            "Verify whether this service is installed or managed by another mechanism."
    fi
}

check_service "SSH Service" sshd.service ssh.service
check_service "Apache Service" httpd.service apache2.service
check_service "cPanel Service" cpanel.service cpanel
check_service "cPHulk Service" cphulkd.service cphulkd
check_service "Cron Service" crond.service cron.service

if systemctl list-unit-files 2>/dev/null |
   awk '{print $1}' |
   grep -Eq '^(mariadb|mysqld|mysql)\.service$'; then

    DB_SERVICE="$(systemctl list-unit-files 2>/dev/null |
        awk '{print $1}' |
        grep -E '^(mariadb|mysqld|mysql)\.service$' |
        head -1)"

    DB_STATE="$(systemctl is-active "$DB_SERVICE" 2>/dev/null)"

    if [ "$DB_STATE" = "active" ]; then
        add_result "MySQL / MariaDB Service" "PASS" \
            "$DB_SERVICE is active." \
            "Keep the database service maintained and monitor resource usage."
    else
        add_result "MySQL / MariaDB Service" "WARN" \
            "$DB_SERVICE is $DB_STATE." \
            "Confirm whether the database service is expected to be running."
    fi
else
    add_result "MySQL / MariaDB Service" "INFO" \
        "No MySQL/MariaDB systemd service was detected." \
        "Verify database service status if a local database is expected."
fi

section_end

# ============================================================
# 20. CloudLinux Security
# ============================================================

section_start "20. CloudLinux Security"

CLOUDLINUX="no"

if rpm -q cloudlinux-release >/dev/null 2>&1 ||
   [ -f /etc/sysconfig/cloudlinux ] ||
   [ -e /proc/lve/list ]; then
    CLOUDLINUX="yes"
fi

if [ "$CLOUDLINUX" = "no" ]; then

    add_result "CloudLinux Detection" "INFO" \
        "CloudLinux was not detected. CloudLinux-specific checks were skipped." \
        "No CloudLinux action is required on a non-CloudLinux server."

else

    add_result "CloudLinux Detection" "PASS" \
        "CloudLinux appears to be installed." \
        "Continue monitoring CloudLinux isolation and resource-management features."

    CLOUDLINUX_VERSION=""

    if command -v cldetect >/dev/null 2>&1; then
        CLOUDLINUX_VERSION="$(cldetect --get-version 2>/dev/null | head -1)"
    fi

    if [ -z "$CLOUDLINUX_VERSION" ] && rpm -q cloudlinux-release >/dev/null 2>&1; then
        CLOUDLINUX_VERSION="$(rpm -q cloudlinux-release 2>/dev/null)"
    fi

    add_result "CloudLinux Version" "INFO" \
        "${CLOUDLINUX_VERSION:-Unable to determine CloudLinux version.}" \
        "Keep CloudLinux updated through the approved maintenance process."

    add_result "CloudLinux Kernel" "INFO" \
        "$(uname -r)" \
        "Ensure the running CloudLinux kernel is within the approved patch baseline."

    if command -v cagefsctl >/dev/null 2>&1; then
        CAGEFS_STATUS="$(cagefsctl --cagefs-status 2>/dev/null)"

        if printf '%s\n' "$CAGEFS_STATUS" | grep -qiE 'enabled|started|mounted'; then
            add_result "CageFS" "PASS" \
                "CageFS status indicates an enabled/active configuration." \
                "Keep CageFS enabled for hosted-user isolation."
        else
            add_result "CageFS" "WARN" \
                "CageFS status did not clearly indicate an enabled/active state." \
                "Review CageFS status in CloudLinux."
        fi

        printf '<h3>CageFS Status</h3><pre>%s</pre>\n' \
            "$(html_escape "$CAGEFS_STATUS")" >> "$REPORT_FILE"
    else
        add_result "CageFS" "WARN" \
            "cagefsctl was not found." \
            "Verify CageFS installation and configuration."
    fi

    if [ -e /proc/lve/list ]; then
        LVE_COUNT="$(grep -c '^' /proc/lve/list 2>/dev/null)"

        add_result "LVE" "PASS" \
            "The CloudLinux LVE interface /proc/lve/list is available (${LVE_COUNT} line(s))." \
            "Continue monitoring LVE resource controls and account limits."
    else
        add_result "LVE" "WARN" \
            "CloudLinux LVE interface /proc/lve/list was not detected." \
            "Verify CloudLinux LVE functionality."
    fi

    ALT_PHP_FOUND=0

    for ALT_PHP_INI in /opt/alt/php*/etc/php.ini; do
        [ -f "$ALT_PHP_INI" ] || continue

        ALT_PHP_FOUND=1

        ALT_PHP_VERSION="$(basename "$(dirname "$(dirname "$ALT_PHP_INI")")")"
        ALT_DISABLE_FUNCTIONS="$(grep -Ei '^[[:space:]]*disable_functions[[:space:]]*=' "$ALT_PHP_INI" 2>/dev/null |
            tail -1 | cut -d= -f2- | sed 's/^[[:space:]]*//')"

        if [ -n "$ALT_DISABLE_FUNCTIONS" ]; then
            add_result "Alt-PHP $ALT_PHP_VERSION - disable_functions" "PASS" \
                "disable_functions is configured." \
                "Review Alt-PHP restrictions periodically."
        else
            add_result "Alt-PHP $ALT_PHP_VERSION - disable_functions" "WARN" \
                "disable_functions is empty or not explicitly configured." \
                "Review Alt-PHP PHP security settings."
        fi
    done

    if [ "$ALT_PHP_FOUND" -eq 0 ]; then
        add_result "Alt-PHP" "INFO" \
            "No Alt-PHP php.ini files were detected." \
            "Verify PHP Selector/Alt-PHP installation if expected."
    fi

    if command -v selectorctl >/dev/null 2>&1; then
        PHP_SELECTOR_OUTPUT="$(selectorctl --interpreter=php --list 2>/dev/null)"

        if [ -n "$PHP_SELECTOR_OUTPUT" ]; then
            add_result "PHP Selector" "PASS" \
                "PHP Selector information was available through selectorctl." \
                "Keep supported PHP versions maintained and remove obsolete versions where appropriate."

            printf '<h3>PHP Selector</h3><pre>%s</pre>\n' \
                "$(html_escape "$PHP_SELECTOR_OUTPUT")" >> "$REPORT_FILE"
        else
            add_result "PHP Selector" "INFO" \
                "selectorctl is present but returned no PHP version listing." \
                "Review PHP Selector configuration."
        fi
    else
        add_result "PHP Selector" "INFO" \
            "selectorctl was not detected." \
            "Verify whether PHP Selector is installed/required."
    fi

    if command -v dbctl >/dev/null 2>&1 ||
       command -v dbtop >/dev/null 2>&1 ||
       rpm -q governor-mysql >/dev/null 2>&1; then

        add_result "MySQL Governor" "INFO" \
            "CloudLinux MySQL Governor components were detected." \
            "Review MySQL Governor resource controls and database workload monitoring."

    else
        add_result "MySQL Governor" "INFO" \
            "MySQL Governor components were not detected." \
            "Verify whether MySQL Governor is installed for this CloudLinux edition."
    fi

    MOD_LSAPI=""

    if command -v httpd >/dev/null 2>&1; then
        MOD_LSAPI="$(httpd -M 2>/dev/null | grep -i 'lsapi_module')"
    fi

    if [ -n "$MOD_LSAPI" ]; then
        add_result "mod_lsapi" "PASS" \
            "CloudLinux mod_lsapi appears to be loaded." \
            "Keep the approved PHP handler configuration maintained."
    else
        add_result "mod_lsapi" "INFO" \
            "mod_lsapi was not detected in the Apache loaded module list." \
            "Verify the intended PHP handler configuration."
    fi

    PROC_HIDE_PID=""

    if mount 2>/dev/null | grep -qE 'proc on /proc .*hidepid='; then
        PROC_HIDE_PID="$(mount 2>/dev/null | grep -E 'proc on /proc .*hidepid=' | head -1)"
    fi

    if [ -n "$PROC_HIDE_PID" ]; then
        add_result "proc hidepid" "PASS" \
            "A hidepid option was detected on the /proc mount." \
            "Keep process visibility restricted according to the CloudLinux security baseline."
    else
        add_result "proc hidepid" "INFO" \
            "No hidepid option was detected on the /proc mount." \
            "Review process visibility requirements for the server."
    fi

    if systemctl list-unit-files 2>/dev/null |
       awk '{print $1}' |
       grep -Eq '^(lvestats|lvestats.service)$'; then

        LVE_STATS_SERVICE="$(systemctl list-unit-files 2>/dev/null |
            awk '{print $1}' |
            grep -E '^(lvestats|lvestats.service)$' |
            head -1)"

        LVE_STATS_STATE="$(systemctl is-active "$LVE_STATS_SERVICE" 2>/dev/null)"

        if [ "$LVE_STATS_STATE" = "active" ]; then
            add_result "LVE Stats Service" "PASS" \
                "$LVE_STATS_SERVICE is active." \
                "Keep CloudLinux resource statistics available for monitoring."
        else
            add_result "LVE Stats Service" "WARN" \
                "$LVE_STATS_SERVICE is $LVE_STATS_STATE." \
                "Verify whether LVE statistics service should be running."
        fi
    else
        add_result "LVE Stats Service" "INFO" \
            "LVE statistics service was not identified through systemd." \
            "Verify CloudLinux statistics configuration if required."
    fi

    if command -v cldiag >/dev/null 2>&1; then
        add_result "CloudLinux Diagnostics" "PASS" \
            "cldiag is available." \
            "Use cldiag during approved troubleshooting and maintenance."
    else
        add_result "CloudLinux Diagnostics" "INFO" \
            "cldiag was not detected." \
            "Verify CloudLinux diagnostic tooling if required."
    fi

fi

section_end

# ============================================================
# Summary
# ============================================================

cat >> "$REPORT_FILE" <<EOF
</div>

<footer>
cPanel / WHM Linux Security Audit v$(html_escape "$SCRIPT_VERSION")<br>
Generated: $(html_escape "$REPORT_TIME")<br>
This report is an audit baseline. It does not perform remediation.
</footer>

<script>
document.getElementById("pass-count").textContent = "$(html_escape "$PASS_COUNT")";
document.getElementById("warn-count").textContent = "$(html_escape "$WARN_COUNT")";
document.getElementById("fail-count").textContent = "$(html_escape "$FAIL_COUNT")";
document.getElementById("info-count").textContent = "$(html_escape "$INFO_COUNT")";
</script>

</body>
</html>
EOF

echo
echo "============================================================"
echo "AUDIT COMPLETED"
echo "============================================================"
echo "PASS : $PASS_COUNT"
echo "WARN : $WARN_COUNT"
echo "FAIL : $FAIL_COUNT"
echo "INFO : $INFO_COUNT"
echo
echo "HTML Report:"
echo "$REPORT_FILE"
echo
echo "No remediation or service/configuration changes were performed."