VulnWhisperer: Building a Unified Vulnerability Intelligence Pipeline from Fragmented Security Tools
Hook
Most security teams spend more time wrestling with vulnerability data formats than actually fixing vulnerabilities. VulnWhisperer solves this by creating a unified ETL pipeline that normalizes Nessus, Qualys, and OpenVAS reports into a single ElasticSearch index with pre-built analytics dashboards.
Context
Enterprise security operations typically deploy multiple vulnerability scanners—Nessus for network scanning, Qualys for continuous monitoring, OpenVAS for budget-conscious internal scans. Each tool generates reports in proprietary formats: Nessus outputs XML with nested plugin structures, Qualys uses a completely different XML schema with QID references, and OpenVAS produces its own unique format. Security analysts face an impossible choice: manually reconcile these disparate data sources in spreadsheets, pay six figures for a commercial vulnerability management platform, or build custom integrations that inevitably become unmaintainable.
VulnWhisperer emerged from this operational pain point at Austin Security, where the team needed centralized vulnerability analytics without enterprise software budgets. The tool implements a classic ETL (Extract-Transform-Load) pattern specifically optimized for vulnerability data: it extracts scan results via scanner APIs, transforms them through Logstash normalization pipelines, and loads everything into ElasticSearch for unified querying and visualization. The genius isn't in novel architecture—it's in providing production-ready Logstash configurations and Kibana dashboards that would otherwise take weeks to build from scratch.
Technical Insight
VulnWhisperer's architecture centers on a Python-based extraction layer that speaks each scanner's native API, outputting normalized JSON files that Logstash can ingest predictably. The tool runs as a scheduled service that polls each configured scanner, downloads new vulnerability data, and writes timestamped JSON files to a designated directory structure that Logstash monitors.
Here's how the Nessus extraction works under the hood:
# Simplified example of VulnWhisperer's Nessus data extraction
from tenable.sc import TenableSC
import json
import os
class NessusSync:
def __init__(self, config):
self.sc = TenableSC(config['host'])
self.sc.login(config['username'], config['password'])
self.output_dir = config['write_path']
def process_scan(self, scan_id):
# Extract vulnerability results from Nessus API
vulns = self.sc.analysis.vulns(
('pluginID', '!=', '0'),
tool='vulndetails'
)
# Normalize to VulnWhisperer's schema
normalized = []
for vuln in vulns:
record = {
'scan_id': scan_id,
'plugin_id': vuln['pluginID'],
'severity': self._map_severity(vuln['severity']),
'host': vuln['ip'],
'port': vuln['port'],
'vulnerability': vuln['pluginName'],
'solution': vuln.get('solution', ''),
'cvss_base_score': vuln.get('baseScore', 0),
'cve': vuln.get('cve', []),
'scan_date': vuln['lastSeen']
}
normalized.append(record)
# Write to file that Logstash will ingest
output_file = f"{self.output_dir}/nessus_{scan_id}_{timestamp}.json"
with open(output_file, 'w') as f:
for record in normalized:
f.write(json.dumps(record) + '\n')
The magic happens in the Logstash pipeline configurations, which VulnWhisperer provides pre-built for each scanner. These pipelines perform critical transformations: mapping vendor-specific severity ratings to a unified scale (Critical/High/Medium/Low), extracting CVE identifiers into structured arrays for cross-referencing, enriching records with asset metadata, and creating consistent field names across all scanner types. A Nessus "Risk Factor" becomes the same "severity" field as Qualys's "Severity Level," enabling unified queries like "severity:Critical" regardless of source scanner.
The Logstash configuration for Nessus processing includes sophisticated parsing logic:
filter {
if [type] == "nessus" {
json {
source => "message"
}
# Normalize severity across all scanners
if [risk_factor] == "Critical" or [severity] == "5" {
mutate {
add_field => { "vuln_severity" => "Critical" }
add_field => { "severity_code" => "5" }
}
}
# Extract CVEs into searchable array
if [cve] {
mutate {
split => { "cve" => "," }
}
}
# Calculate vulnerability age for SLA tracking
ruby {
code => "
first_found = Time.parse(event.get('first_found'))
age_days = ((Time.now - first_found) / 86400).to_i
event.set('vuln_age_days', age_days)
"
}
}
}
This normalization enables powerful analytics that would be impossible with raw scanner exports. The included Kibana dashboards visualize vulnerability trends over time, track mean-time-to-remediation by severity, identify the most vulnerable asset groups, and correlate CVEs with CVSS scores across your entire scanning infrastructure. Security teams can finally answer questions like "How many critical vulnerabilities are older than 30 days?" or "Which business unit has the worst patching velocity?" with a single ElasticSearch query.
The Docker Compose deployment bundles ElasticSearch, Kibana, and Logstash with all pipelines pre-configured, which is transformative for teams without dedicated ELK expertise. Running docker-compose up gives you a complete vulnerability analytics platform in minutes rather than the days typically required for ELK stack setup. The compose file automatically loads Kibana visualizations and index patterns, so dashboards appear immediately with real data flowing from your first scanner sync.
Gotcha
VulnWhisperer's most significant limitation is its frozen-in-time technology stack. The project is locked to Python 2.7, which reached end-of-life in January 2020 and no longer receives security patches—ironic for a security tool. The bundled ElasticStack version (6.6) is several major versions behind the current 8.x release, missing years of performance improvements, security hardening, and new query capabilities. Any team with compliance requirements or modern Python 3.x infrastructure will face immediate blockers. Even the maintainers acknowledge the documentation is outdated as of 2022, with promised code reviews and overhauls that haven't materialized.
Scanner support is narrow compared to commercial alternatives. If you're running Rapid7 InsightVM, Burp Suite Enterprise, or any AppSec scanning tools like Checkmarx or Veracode, VulnWhisperer can't help you. The roadmap promises additional scanners but hasn't seen significant expansion in years. The Jira integration, while conceptually valuable for closed-loop remediation tracking, requires manual configuration that the outdated documentation makes challenging to implement correctly. Teams should plan on reading source code to understand current capabilities rather than relying on GitHub documentation.
Verdict
Use VulnWhisperer if: you're operating Nessus, Qualys, or OpenVAS in environments where Python 2.7 is acceptable (lab environments, non-production networks), you need centralized vulnerability analytics without budget for Splunk or commercial SIEM platforms, you have existing ELK infrastructure and just need the normalization layer, or you're willing to fork and modernize the codebase to Python 3.x yourself. The pre-built Kibana dashboards and Logstash pipelines still provide genuine value for smaller security teams who understand the technical debt they're accepting. Skip if: you require Python 3.x and modern ElasticSearch versions for security or compliance reasons, you need scanning tools beyond the four supported platforms, you expect active maintenance and reliable documentation, you're integrating into enterprise ITSM workflows that demand production-grade support, or you need AppSec scanner integration for DevSecOps pipelines. Consider actively maintained alternatives like DefectDojo or Faraday instead, which offer broader scanner support and modern Python implementations.