Clam AV - Hardening
I am in the process of ditching Microsoft Windows, it's not that I don't like it - I'm neutral on that front but I am moving to Linux. There are a number of reasons
- Privacy - Microsoft Windows is noisy as hell - Linux is not
- I need to become instinctive on what I am doing with Linux - making it my daily will help
- Linux is transparent or I believe so - I will leave it at that.
- Hardware longevity - replacing a laptop every 5 to 7 years is bloody wasteful
As such I don't believe the "why do you need antivirus on Linux" line. The fact that it runs nearly all the worlds' servers and has a growing footprint in desktops and laptops means it will eventually gain somebodies attention with malicious intent - if it hasn't already done so. I mean derivatives of it run routers, just about every IOT device, you name it.
So, I went with the standard solution for Linux antivirus protection.
I have gotten around to hardening it iaw the recommendations of the AI (the smarter of the 5 I have access to - yes it costs - but I learn heaps - yes, it's smarter than me). Yes, I have been writing a lot of code lately in addition to fixing my servers. Learn something new, code rewrite, find out your assumptions are wrong, code rewrite. It's never ending but I love it.
The following script is its recommendations. I have shared it to give anyone who reads this some ideas. I DONT say it's right but it's better than the base configuration.
So here it is
#!/bin/bash
# Harden ClamAV configuration for Debian/Mint systems
# Idempotent: safely re-runnable, only applies changes if missing
# Audit-style comments included for compliance traceability
# Root check added: script must be run as root to modify system configs
set -euo pipefail
# --- Root privilege check ---
if [[ "${EUID}" -ne 0 ]]; then
echo "❌ This script must be run as root."
exit 1
fi
CLAMD_CONF="/etc/clamav/clamd.conf"
FRESHCLAM_CONF="/etc/clamav/freshclam.conf"
LOGFILE="/var/log/clamav/harden_clamav.log"
# Ensure logfile exists
mkdir -p "$(dirname "$LOGFILE")"
touch "$LOGFILE"
log() {
echo "$(date '+%F %T') : $*" | tee -a "$LOGFILE"
}
# Function to ensure a config directive exists and is set correctly
ensure_config() {
local file="$1"
local key="$2"
local value="$3"
if grep -qE "^[[:space:]]*$key" "$file"; then
# Replace existing line
sed -i "s|^[[:space:]]*$key.*|$key $value|" "$file"
log "Updated $key in $file to $value"
else
# Append if missing
echo "$key $value" >> "$file"
log "Added $key $value to $file"
fi
}
log "=== Hardening ClamAV configuration ==="
# --- Socket permissions ---
ensure_config "$CLAMD_CONF" "LocalSocketMode" "660"
ensure_config "$CLAMD_CONF" "LocalSocketGroup" "clamav"
# --- Logging ---
ensure_config "$CLAMD_CONF" "LogVerbose" "yes"
ensure_config "$CLAMD_CONF" "LogSyslog" "yes"
ensure_config "$CLAMD_CONF" "LogFacility" "LOG_LOCAL6"
# --- Exclusions ---
for path in "^/proc/" "^/sys/" "^/dev/" "^/run/" "^/var/lib/docker/" "^/var/lib/containers/" "^/var/lib/mysql/" "^/var/lib/postgresql/" "^/var/cache/apt/archives/" "^/var/infected/"; do
if ! grep -q "ExcludePath $path" "$CLAMD_CONF"; then
echo "ExcludePath $path" >> "$CLAMD_CONF"
log "Added ExcludePath $path"
fi
done
# --- Alerts ---
for key in AlertEncryptedArchive AlertEncryptedDoc AlertOLE2Macros AlertPhishingSSLMismatch AlertPhishingCloak; do
ensure_config "$CLAMD_CONF" "$key" "yes"
done
# --- Database hygiene ---
ensure_config "$CLAMD_CONF" "OfficialDatabaseOnly" "yes"
ensure_config "$CLAMD_CONF" "FailIfCvdOlderThan" "7"
# --- Freshclam checks ---
ensure_config "$FRESHCLAM_CONF" "Checks" "24"
# --- On-Access Scanning (workstation protection) ---
# Enable scanning of user home directories only
ensure_config "$CLAMD_CONF" "OnAccessIncludePath" "/home"
ensure_config "$CLAMD_CONF" "OnAccessPrevention" "yes"
# Exclude system dirs from on-access scanning
for path in "/proc" "/sys" "/dev" "/run"; do
if ! grep -q "OnAccessExcludePath $path" "$CLAMD_CONF"; then
echo "OnAccessExcludePath $path" >> "$CLAMD_CONF"
log "Added OnAccessExcludePath $path"
fi
done
log "=== Restarting ClamAV services ==="
# Restart services
systemctl restart clamav-daemon clamav-freshclam || {
log "ERROR: Failed to restart ClamAV services"
exit 1
}
# Verify status
if systemctl is-active --quiet clamav-daemon && systemctl is-active --quiet clamav-freshclam; then
log "SUCCESS: ClamAV services restarted and are active"
else
log "ERROR: One or more ClamAV services failed to start"
systemctl status clamav-daemon clamav-freshclam | tee -a "$LOGFILE"
exit 1
fi
log "=== Harden ClamAV script completed successfully ==="
As you can see - it didn't change too much.
What’s Included
- Root check: prevents non‑root execution.
- PidFile enabled:
/var/run/clamav/clamd.pidfor monitoring. - LogFileMaxSize set to 50M: prevents runaway logs.
- DetectPUA enabled: catches adware/toolbars.
- OnAccessMaxFileSize bumped to 10 MB: broader coverage for downloads.
- OnAccessIncludePath
/home: protects user data. - Exclusions: system dirs, DBs, container storage, apt cache, quarantine.
- Alerts: encrypted archives/docs, macros, phishing mismatches/cloaks.
- Database hygiene: official DB only, fail if older than 7 days.
- Service restart & verification: ensures daemon and updater are active.
- Audit log:
/var/log/clamav/harden_clamav.logrecords all changes.
Proof it works
2025-11-17 16:48:39 : === Hardening ClamAV configuration ===
2025-11-17 16:48:39 : Updated LocalSocketMode in /etc/clamav/clamd.conf to 660
2025-11-17 16:48:39 : Updated LocalSocketGroup in /etc/clamav/clamd.conf to clamav
2025-11-17 16:48:39 : Added PidFile /var/run/clamav/clamd.pid to /etc/clamav/clamd.conf
2025-11-17 16:48:39 : Updated LogFile in /etc/clamav/clamd.conf to /var/log/clamav/clamav.log
2025-11-17 16:48:39 : Added LogFileMaxSize 50M to /etc/clamav/clamd.conf
2025-11-17 16:48:39 : Updated LogTime in /etc/clamav/clamd.conf to yes
2025-11-17 16:48:40 : Updated LogVerbose in /etc/clamav/clamd.conf to yes
2025-11-17 16:48:40 : Updated LogSyslog in /etc/clamav/clamd.conf to yes
2025-11-17 16:48:40 : Updated LogFacility in /etc/clamav/clamd.conf to LOG_LOCAL6
2025-11-17 16:48:40 : Updated LogRotate in /etc/clamav/clamd.conf to yes
2025-11-17 16:48:40 : Updated AlertEncryptedArchive in /etc/clamav/clamd.conf to yes
2025-11-17 16:48:40 : Updated AlertEncryptedDoc in /etc/clamav/clamd.conf to yes
2025-11-17 16:48:40 : Updated AlertOLE2Macros in /etc/clamav/clamd.conf to yes
2025-11-17 16:48:40 : Updated AlertPhishingSSLMismatch in /etc/clamav/clamd.conf to yes
2025-11-17 16:48:40 : Updated AlertPhishingCloak in /etc/clamav/clamd.conf to yes
2025-11-17 16:48:40 : Updated OfficialDatabaseOnly in /etc/clamav/clamd.conf to yes
2025-11-17 16:48:40 : Updated FailIfCvdOlderThan in /etc/clamav/clamd.conf to 7
2025-11-17 16:48:40 : Added ConcurrentDatabaseReload yes to /etc/clamav/clamd.conf
2025-11-17 16:48:40 : Updated SelfCheck in /etc/clamav/clamd.conf to 3600
2025-11-17 16:48:40 : Updated AlgorithmicDetection in /etc/clamav/clamd.conf to yes
2025-11-17 16:48:40 : Updated DetectPUA in /etc/clamav/clamd.conf to yes
2025-11-17 16:48:40 : Updated MaxScanSize in /etc/clamav/clamd.conf to 104857600
2025-11-17 16:48:40 : Updated MaxFileSize in /etc/clamav/clamd.conf to 26214400
2025-11-17 16:48:40 : Updated MaxRecursion in /etc/clamav/clamd.conf to 16
2025-11-17 16:48:40 : Updated MaxFiles in /etc/clamav/clamd.conf to 10000
2025-11-17 16:48:40 : Updated OnAccessMaxFileSize in /etc/clamav/clamd.conf to 10485760
2025-11-17 16:48:40 : Updated OnAccessIncludePath in /etc/clamav/clamd.conf to /home
2025-11-17 16:48:40 : Updated OnAccessPrevention in /etc/clamav/clamd.conf to yes
2025-11-17 16:48:40 : Updated Checks in /etc/clamav/freshclam.conf to 24
2025-11-17 16:48:40 : === Restarting ClamAV services ===
2025-11-17 16:48:41 : SUCCESS: ClamAV services restarted and are active
2025-11-17 16:48:41 : === Harden ClamAV script completed successfully ===
Unlike Windows Professional and above you don't have to turn ASR on and a lot of services off with or without caveats. Like I said transparent.
Next job testing the SSH key reset/rotation script that the AI and I rewrote last night whilst I should have been asleep. It's much better to break your laptop than your server 😄
One massive learning on moving to Linux is none of the major cloud storage players provide Linux code to access their storage servers - which includes Microsoft, Google, Proton to name 3 - I mean what the hell.
To be honest for most people Linux would be a much safer option.
On a side note - the docker version 29 saga continues - I cut my losses but...
https://github.com/portainer/portainer/issues/12925#issuecomment-3540552277
But what the hell do I know.
#enoughsaid