Why Automated Vulnerability Scanning Is Non-Negotiable in 2026
The numbers tell a pretty grim story: over 5,500 Linux kernel CVEs were reported in 2025, and 2026 is on pace to blow past that. January alone logged more than 2,800 new CVEs across all platforms. That works out to roughly 8–9 new kernel vulnerabilities every single day. Manual scanning isn't just impractical at this point — it's a liability.
And here's the part that really gets me: 79% of Linux attacks in 2025 used no malware at all. Attackers just exploited misconfigurations, unpatched services, and stolen credentials. If your vulnerability management strategy amounts to running a scan "every quarter" or "when we remember," you're almost certainly running production systems with known, exploitable flaws that automated scanners could've caught in minutes.
I've seen this firsthand — a team that hadn't scanned in six weeks got hit by a CVE that had a public exploit for over a month. Totally preventable.
So, let's dive in. This guide walks you through four powerful open-source vulnerability scanners — OpenVAS/GVM, Trivy, Vuls, and Nmap with Vulners — and shows you how to deploy them in a layered, automated scanning pipeline on Linux. Each tool covers a different slice of the attack surface: network services, installed packages, container images, and targeted CVE discovery.
Choosing the Right Scanner for Your Stack
No single scanner catches everything. Each tool excels in a specific domain, and combining them gives you comprehensive coverage with minimal blind spots.
| Scanner | Primary Use | Scan Target | Agent Required | Best For |
|---|---|---|---|---|
| OpenVAS/GVM | Network vulnerability assessment | Hosts, services, network devices | No (network-based) | Infrastructure-wide authenticated scanning |
| Trivy | Package and container scanning | OS packages, container images, IaC, filesystems | No (single binary) | CI/CD pipelines, container security |
| Vuls | Agentless host scanning | OS packages, libraries, middleware | No (SSH-based) | Multi-host fleet scanning without agents |
| Nmap + Vulners | Targeted CVE discovery | Open ports, service versions | No (network-based) | Quick reconnaissance and perimeter audits |
The approach I'd recommend is layering these tools: use OpenVAS for deep authenticated network scans on a weekly schedule, Trivy in every CI/CD pipeline for container and dependency scanning, Vuls for daily agentless host fleet checks, and Nmap for on-demand perimeter audits. That way, you're not relying on any single tool to catch everything.
Setting Up OpenVAS/GVM with Docker
OpenVAS (now part of the Greenbone Vulnerability Manager framework) is the most comprehensive open-source network vulnerability scanner out there, with a database of over 185,000 CVEs across more than 950,000 vulnerability test plugins. The fastest way to get it running in 2026 is via Docker.
Prerequisites
OpenVAS/GVM is hungry for resources — you'll need at least 8 GB of RAM and roughly 21 GB of disk space for the full vulnerability feed. Make sure Docker and Docker Compose are installed:
sudo apt update && sudo apt install -y docker.io docker-compose
sudo systemctl enable --now docker
sudo usermod -aG docker $USER
Deploy the Greenbone Community Edition
# Download the official docker-compose file
curl -f -O https://greenbone.github.io/docs/latest/_static/docker-compose-22.4.yml
# Start the full GVM stack
sudo docker-compose -f docker-compose-22.4.yml -p greenbone-community-edition up -d
# Monitor the feed sync progress (this takes 30-60 minutes on first run)
sudo docker-compose -f docker-compose-22.4.yml -p greenbone-community-edition \
logs -f gvmd
Once the feeds finish syncing, access the web interface at https://localhost:9392. The default credentials are admin/admin — change them immediately (seriously, don't skip this):
# Change the admin password via CLI
sudo docker-compose -f docker-compose-22.4.yml -p greenbone-community-edition \
exec gvmd gvmd --user=admin --new-password='YourStr0ngP@ssword!'
Automate Daily Feed Updates
Vulnerability feeds get updated multiple times per week. Schedule a daily sync so you don't fall behind:
# /etc/cron.d/gvm-feed-sync
0 3 * * * root docker-compose -f /opt/gvm/docker-compose-22.4.yml \
-p greenbone-community-edition exec -T gvmd greenbone-feed-sync \
>> /var/log/gvm-feed-sync.log 2>&1
Running Authenticated Scans
Unauthenticated scans only see what's exposed on the network. Authenticated scans log into targets via SSH and inspect installed packages, which yields dramatically more accurate results. Honestly, the difference in detection quality is night and day.
In the Greenbone web UI, navigate to Configuration → Credentials and create an SSH credential with a dedicated scan account. Then create a target that uses those credentials:
# On each target host, create a restricted scan user
sudo useradd -m -s /bin/bash gvm-scan
sudo mkdir -p /home/gvm-scan/.ssh
# Copy the GVM public key
echo "ssh-ed25519 AAAA... gvm-scanner" | sudo tee /home/gvm-scan/.ssh/authorized_keys
sudo chmod 700 /home/gvm-scan/.ssh
sudo chmod 600 /home/gvm-scan/.ssh/authorized_keys
sudo chown -R gvm-scan:gvm-scan /home/gvm-scan/.ssh
For maximum detection without giving the scan account root access, grant it read access to the package manager database. On Debian/Ubuntu, the gvm-scan user can already run dpkg -l without privileges. On RHEL-based systems, rpm -qa also runs unprivileged. No sudo needed for basic package enumeration.
Scanning Linux Hosts and Containers with Trivy
Trivy is a fast, versatile scanner developed by Aqua Security that can scan container images, filesystem packages, IaC templates, and Git repositories. It runs as a single binary with zero dependencies — no database server, no middleware, nothing. Just download and go.
Critical Security Notice: March 2026 Supply Chain Attack
This one stung. On March 19, 2026, the official aquasecurity/trivy-action GitHub Action was compromised in a supply chain attack. The attacker force-pushed 75 out of 76 version tags, injecting a credential stealer that targeted CI/CD secrets across over 10,000 workflows globally. The compromised Docker Hub images (versions 0.69.4, 0.69.5, 0.69.6, and latest between March 19–23) attempted to dump process memory and exfiltrate SSH keys, cloud credentials, and Docker configurations.
Mitigation steps: Pin GitHub Actions to full commit SHA hashes — never mutable tags. The last known clean release is 0.69.3. If you pulled affected images during that window, rotate all credentials immediately. This incident is a stark reminder that even security tools themselves are supply chain targets. Always verify integrity.
Install Trivy
# Install via the official repository (Debian/Ubuntu)
sudo apt install -y wget apt-transport-https gnupg
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | \
gpg --dearmor | sudo tee /usr/share/keyrings/trivy.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb generic main" | \
sudo tee /etc/apt/sources.list.d/trivy.list
sudo apt update && sudo apt install -y trivy
# Verify the installed version
trivy version
Scan the Local Filesystem for OS Vulnerabilities
# Scan the running host for package vulnerabilities
trivy rootfs / --severity HIGH,CRITICAL --format table
# Scan and output machine-readable JSON for automation
trivy rootfs / --severity HIGH,CRITICAL --format json -o /var/log/trivy-host-scan.json
Scan Container Images Before Deployment
# Scan an image before pushing to production
trivy image nginx:1.27-bookworm --severity HIGH,CRITICAL
# Fail the build if critical vulnerabilities are found (CI/CD gate)
trivy image --exit-code 1 --severity CRITICAL myapp:latest
That --exit-code 1 flag is the magic here — it turns Trivy into a proper CI/CD gate that blocks deployments with critical vulns.
Scan Infrastructure as Code
# Scan Terraform, Kubernetes manifests, Dockerfiles for misconfigurations
trivy config ./infrastructure/ --severity HIGH,CRITICAL
Agentless Multi-Host Scanning with Vuls
Vuls is an open-source, agentless vulnerability scanner written in Go. It connects to remote hosts via SSH, checks installed packages against multiple vulnerability databases (NVD, OVAL, distribution advisories), and generates comprehensive reports — all without installing anything on the targets. If you manage a fleet of Linux servers, this one's a game-changer.
Install Vuls and Its Dependencies
# Install Go (required for Vuls)
sudo apt install -y golang-go git
# Set up the Vuls workspace
mkdir -p ~/vuls && cd ~/vuls
# Install vulnerability databases
go install github.com/vulsio/go-cve-dictionary/cmd/go-cve-dictionary@latest
go install github.com/vulsio/goval-dictionary/cmd/goval-dictionary@latest
go install github.com/vulsio/go-exploitdb/cmd/go-exploitdb@latest
# Install Vuls itself
go install github.com/future-architect/vuls/cmd/vuls@latest
# Fetch CVE data from NVD (this takes several minutes)
go-cve-dictionary fetch nvd --dbpath ~/vuls/cve.sqlite3
# Fetch OVAL data for your target distributions
goval-dictionary fetch ubuntu 22 24 --dbpath ~/vuls/oval.sqlite3
goval-dictionary fetch redhat 8 9 --dbpath ~/vuls/oval.sqlite3
Fair warning: the initial NVD fetch can take a while. Grab some coffee.
Configure Scan Targets
Create a config.toml file in your Vuls workspace:
# ~/vuls/config.toml
[servers]
[servers.web-prod-01]
host = "192.168.1.10"
port = "22"
user = "vuls-scan"
keyPath = "/home/admin/.ssh/vuls_ed25519"
scanMode = ["fast"]
[servers.db-prod-01]
host = "192.168.1.20"
port = "22"
user = "vuls-scan"
keyPath = "/home/admin/.ssh/vuls_ed25519"
scanMode = ["fast-root"]
[servers.db-prod-01.optional]
sudo = true
The fast scan mode doesn't require root and works by checking package versions. The fast-root mode uses sudo for deeper inspection — use it on hosts where you need more thorough coverage (database servers, for instance).
Run a Scan and Generate Reports
# Validate the configuration
vuls configtest -config ~/vuls/config.toml
# Run the scan
vuls scan -config ~/vuls/config.toml
# Generate a terminal report
vuls report -config ~/vuls/config.toml -format-full-text
# Generate JSON for integration with other tools
vuls report -config ~/vuls/config.toml -format-json -to-localfile \
-output-path ~/vuls/results/
Automate Daily Scans with Cron
# /etc/cron.d/vuls-daily-scan
PATH=/usr/local/go/bin:/usr/local/bin:/usr/bin:/bin
GOPATH=/home/admin/go
# Update vulnerability databases at 1 AM
0 1 * * * admin go-cve-dictionary fetch nvd --dbpath /home/admin/vuls/cve.sqlite3 > /var/log/vuls-cve-update.log 2>&1
# Run scan at 2 AM and send report to Slack
0 2 * * * admin /home/admin/go/bin/vuls scan -config /home/admin/vuls/config.toml && \
/home/admin/go/bin/vuls report -config /home/admin/vuls/config.toml \
-to-slack -cvss-over=7.0 > /var/log/vuls-scan.log 2>&1
Targeted CVE Discovery with Nmap and Vulners
Nmap combined with the Vulners NSE script gives you a lightweight way to discover known CVEs in exposed network services. Unlike the comprehensive scanners above, Nmap is perfect for quick perimeter audits and on-demand reconnaissance of specific targets. Think of it as the "quick check" in your toolkit.
Install and Run a Vulners Scan
# Install Nmap (comes with the vulners script included)
sudo apt install -y nmap
# Scan a single host — service version detection is required (-sV)
sudo nmap -sV --script vulners -oA /tmp/scan-webserver 192.168.1.10
# Filter for high-severity CVEs only (CVSS >= 7.0)
sudo nmap -sV --script vulners --script-args mincvss=7.0 192.168.1.10
# Scan an entire subnet for critical vulnerabilities
sudo nmap -sV --script vulners --script-args mincvss=9.0 \
-oX /var/log/nmap-subnet-scan.xml 192.168.1.0/24
Offline Scanning with Vulscan
The vulners script queries an external API, which isn't ideal for air-gapped environments. The vulscan NSE script provides an offline alternative that uses locally downloaded vulnerability databases:
# Install vulscan
cd /usr/share/nmap/scripts/
sudo git clone https://github.com/scipag/vulscan.git
sudo nmap --script-updatedb
# Run an offline vulnerability scan
sudo nmap -sV --script vulscan/vulscan.nse -oA /tmp/offline-scan 192.168.1.10
Automate Weekly Perimeter Audits
# /etc/cron.d/nmap-weekly-audit
0 4 * * 1 root nmap -sV --script vulners --script-args mincvss=7.0 \
-oX /var/log/nmap/perimeter-$(date +\%F).xml \
-iL /etc/nmap/perimeter-targets.txt >> /var/log/nmap/scan.log 2>&1
Integrating Vulnerability Scanning into CI/CD Pipelines
Shifting vulnerability scanning left into the build pipeline catches issues before they ever reach production. The key principle is simple: fail the build on critical vulnerabilities, warn on high-severity ones, and report everything to a centralized dashboard.
Getting this right saves you from so many 2 AM incidents. Trust me on that one.
GitHub Actions Example with Trivy
After the March 2026 supply chain attack on the official Trivy action, you'll want to either pin to a verified commit SHA or (my preference) just install Trivy directly:
# .github/workflows/security-scan.yml
name: Security Scan
on:
push:
branches: [main]
pull_request:
schedule:
- cron: "0 6 * * 1" # Weekly Monday 6 AM rescan
jobs:
trivy-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Trivy (direct binary — no third-party action)
run: |
sudo apt-get install -y wget
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | \
gpg --dearmor | sudo tee /usr/share/keyrings/trivy.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] \
https://aquasecurity.github.io/trivy-repo/deb generic main" | \
sudo tee /etc/apt/sources.list.d/trivy.list
sudo apt-get update && sudo apt-get install -y trivy
- name: Scan container image
run: |
docker build -t myapp:${{ github.sha }} .
trivy image --exit-code 1 --severity CRITICAL \
--format sarif -o trivy-results.sarif \
myapp:${{ github.sha }}
- name: Upload SARIF to GitHub Security
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: trivy-results.sarif
GitLab CI Example
# .gitlab-ci.yml
stages:
- build
- scan
vulnerability-scan:
stage: scan
image: aquasec/trivy:0.69.3 # Pinned to last known clean version
script:
- trivy image --exit-code 0 --severity HIGH --format json -o gl-container-scanning-report.json $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- trivy image --exit-code 1 --severity CRITICAL $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
artifacts:
reports:
container_scanning: gl-container-scanning-report.json
allow_failure: false
Building a Unified Scanning Pipeline
The real power comes from combining all four tools into a coordinated workflow. Here's a practical architecture that maximizes coverage while keeping operational overhead manageable:
Layered Scanning Schedule
| Layer | Tool | Frequency | Trigger | Scope |
|---|---|---|---|---|
| Build-time | Trivy | Every commit | CI/CD pipeline | Container images, dependencies, IaC |
| Daily host scan | Vuls | Daily at 2 AM | Cron | All Linux servers via SSH |
| Weekly deep scan | OpenVAS/GVM | Weekly | GVM scheduler | Full authenticated network scan |
| Weekly perimeter | Nmap + Vulners | Weekly | Cron | Internet-facing services |
Centralized Reporting with a Webhook Aggregator
Feed scan results from all four tools into a central location. Here's a straightforward approach using a shared directory and a script that consolidates findings:
#!/bin/bash
# /opt/vuln-reports/aggregate.sh
# Consolidate scan results and send a daily digest
REPORT_DIR="/var/log/vuln-scans"
TIMESTAMP=$(date +%F)
DIGEST="${REPORT_DIR}/digest-${TIMESTAMP}.txt"
echo "=== Vulnerability Scan Digest: ${TIMESTAMP} ===" > "$DIGEST"
# Vuls summary
echo -e "\n--- Vuls (Host Packages) ---" >> "$DIGEST"
vuls report -config /home/admin/vuls/config.toml -format-short-text 2>/dev/null >> "$DIGEST"
# Trivy host scan
echo -e "\n--- Trivy (Local Filesystem) ---" >> "$DIGEST"
trivy rootfs / --severity HIGH,CRITICAL --format table 2>/dev/null >> "$DIGEST"
# Nmap perimeter findings
echo -e "\n--- Nmap (Perimeter) ---" >> "$DIGEST"
if [ -f "${REPORT_DIR}/nmap/perimeter-${TIMESTAMP}.xml" ]; then
nmap -oG - "${REPORT_DIR}/nmap/perimeter-${TIMESTAMP}.xml" 2>/dev/null >> "$DIGEST"
fi
# Send via webhook (Slack, Teams, or email)
curl -X POST -H "Content-type: application/json" \
-d "{\"text\": \"Daily vulnerability digest generated. $(grep -c CVE "$DIGEST") CVEs found.\"}" \
"${SLACK_WEBHOOK_URL}"
It's not fancy, but it works. You can always swap in something more sophisticated (like DefectDojo or Faraday) down the road once your process matures.
Hardening Your Scanners Themselves
The March 2026 Trivy supply chain compromise proved something uncomfortable: vulnerability scanners are high-value targets. Think about it — a compromised scanner runs with privileged access across your entire infrastructure. That's basically the keys to the kingdom.
Here's what you should do to protect them:
- Isolate the scanning infrastructure. Run OpenVAS and Vuls on a dedicated management VLAN with strict firewall rules. The scanner should be able to reach targets, but targets shouldn't be able to reach back into the scanner.
- Pin versions and verify checksums. Never use
latesttags for scanner images. Pin to specific versions and verify SHA256 checksums against official release pages. Yes, it's tedious. Do it anyway. - Use dedicated scan credentials. Create purpose-built accounts with minimal privileges for each scanner. Never reuse admin or service account credentials.
- Monitor the scanners. Watch for unexpected outbound connections, elevated CPU usage, or changes to scanner binaries. Treat scanner hosts with the same rigor as production systems.
- Keep scanners updated. Scanners themselves have vulnerabilities. Subscribe to security advisories for OpenVAS, Trivy, Vuls, and Nmap, and patch promptly.
Frequently Asked Questions
What is the best open-source vulnerability scanner for Linux servers?
There isn't a single "best" scanner — the most effective approach combines multiple tools. OpenVAS/GVM is the most comprehensive for network vulnerability assessment with over 185,000 CVE checks. Trivy excels at container and dependency scanning in CI/CD pipelines. Vuls provides efficient agentless scanning across large server fleets via SSH. For quick perimeter checks, Nmap with the Vulners script offers fast, targeted CVE discovery. Layer all four for maximum coverage.
How often should I run vulnerability scans on Linux production servers?
At minimum: continuous scanning in CI/CD pipelines (every commit), daily lightweight host scans with Vuls or Trivy, weekly deep authenticated scans with OpenVAS, and weekly perimeter audits with Nmap. Critical infrastructure may warrant even more frequent scanning. The key is that scanning should be automated — if it depends on someone remembering to run it, it won't happen consistently.
What is the difference between vulnerability scanning and compliance scanning?
Vulnerability scanning identifies known CVEs in installed software, open services, and dependencies — it answers "what can an attacker exploit?" Compliance scanning (using tools like OpenSCAP against CIS Benchmarks) checks whether system configurations meet a predefined security standard — it answers "does this system meet policy?" Both are essential but address different risks. A system can pass every CIS benchmark check while still running an unpatched version of OpenSSH with a critical CVE.
Is Trivy safe to use after the March 2026 supply chain attack?
Yes, absolutely. The attack targeted the GitHub Action wrapper (aquasecurity/trivy-action) and specific Docker Hub image tags, not the core Trivy binary. To use Trivy safely: install it directly from the official APT/YUM repository or download the binary and verify its checksum, pin to version 0.69.3 or a confirmed clean later release, never use mutable Docker tags like latest, and pin any GitHub Actions to full commit SHA hashes instead of version tags.
Can I run OpenVAS vulnerability scans without root access on target hosts?
Yes. OpenVAS performs network-based scanning from its own host, so it doesn't need root on targets for unauthenticated scans. For authenticated scans (which detect significantly more vulnerabilities), you need an SSH user on the target — but this user doesn't require root either. Package listing commands like dpkg -l (Debian/Ubuntu) and rpm -qa (RHEL/CentOS) run without elevated privileges. Only grant sudo if you need deep scan features like checking running process versions or reading protected configuration files.