With a client for each tool built across the last three articles, the assembly line can finally be assembled: trigger a scan, wait for it, pull the findings, enrich the most severe with a targeted check, and write everything as one report another system can consume.
The algorithm
Python concept: Automated vulnerability assessment
Input: a scanner, a target range, and a prepared scan definition. Output: one machine-readable report of the findings.
- Launch the scan and wait until the scanner reports it is complete.
- Retrieve the findings and group them by severity.
- Select the critical findings for a closer look.
- Run a targeted scanner module against the range to confirm the exposure.
- Assemble the severity summary and the critical findings into one report.
- Write the report as JSON for the next system, a dashboard or a ticket queue.
The pipeline, in code
unified_workflow.py
# unified_workflow.py
import json
def run_assessment(nessus_client, msf_client, scan_id, target_range):
nessus_client.wait_for_completion(scan_id)
vulnerabilities = get_vulnerabilities(nessus_client, scan_id)
critical = [v for v in vulnerabilities if v["severity"] == 4]
print(f"{len(critical)} critical findings from Nessus")
smb = msf_client.modules.use("auxiliary", "scanner/smb/smb_version")
smb["RHOSTS"] = target_range
smb.execute()
report = {
"target_range": target_range,
"severity_summary": summarise_by_severity(vulnerabilities),
"critical_findings": [
{"plugin_name": v["plugin_name"], "host": v.get("hostname", "unknown")}
for v in critical
],
}
with open("assessment_report.json", "w") as f:
json.dump(report, f, indent=2)
print("Report written to assessment_report.json")
run_assessment(nessus_client, msf_client, scan_id=42, target_range="10.0.0.0/24")
Steps 1 to 4 of the algorithm need the live Nessus and Metasploit connections from the last two articles, so that half cannot run here either. Step 5, assembling the report dictionary, and step 6, writing it as JSON, need nothing but data already in memory, and that half runs exactly as written:
build_report.py (steps 5 and 6, tested on their own with synthetic findings)
import json
from nessus_results import summarise_by_severity
def build_report(target_range, vulnerabilities, smb_findings):
critical = [v for v in vulnerabilities if v["severity"] == 4]
report = {
"target_range": target_range,
"severity_summary": summarise_by_severity(vulnerabilities),
"critical_findings": [
{"plugin_name": v["plugin_name"], "host": v.get("hostname", "unknown")}
for v in critical
],
"smb_versions": smb_findings,
}
with open("assessment_report.json", "w") as f:
json.dump(report, f, indent=2)
return report
Sample output and the report file it writes, from 68 synthetic findings including two critical ones
2 critical findings from Nessus
Report written to assessment_report.json
{
"target_range": "10.0.0.0/24",
"severity_summary": {
"Critical": 2, "High": 5, "Medium": 13, "Low": 7, "Info": 41
},
"critical_findings": [
{"plugin_name": "Apache Struts RCE (CVE-2017-5638)", "host": "10.0.0.5"},
{"plugin_name": "SMB Remote Code Execution (MS17-010)", "host": "10.0.0.7"}
],
"smb_versions": [
{"host": "10.0.0.5", "smb_version": "SMBv1", "os": "Windows Server 2008 R2"}
]
}
One command produced a scan, an enrichment check and a machine-readable report. The resulting assessment_report.json is the deliverable: a ticketing system can open one issue per critical finding from it automatically, and next month's assessment becomes a matter of comparing two JSON files rather than re-reading two PDF reports by eye.
Python concept: Why JSON, and not a formatted document
A report in this shape, structured data rather than a formatted document, is built to be read by another program as readily as by a person. A dashboard can ingest it directly, a ticketing system can open one issue per critical finding automatically, and a month-on-month trend becomes a matter of comparing two JSON files rather than re-reading two PDF reports by eye.
When the finding is right there, and nobody acts
Real incident: Equifax, 2017: the scan found it, nobody acted
In 2017, the credit-reporting agency Equifax suffered a breach that exposed the personal data of roughly 147 million people. The way in was a known vulnerability in the Apache Struts web framework, catalogued as CVE-2017-5638, for which a patch had been available since March 2017, months before the breach. Investigations afterward found that Equifax's own scanning had not reliably flagged the vulnerable system, and the patch was never applied to it. A tool could have reported the finding; the organisation never closed the loop between the finding and the fix.
What this teaches: the critical finding the run_assessment() pipeline flags is worthless if nobody acts on it. CVE-2017-5638 is exactly the kind of finding a Nessus or Nexpose scan would mark critical. Equifax shows that the gap an attacker exploits is usually not a gap in scanning technology but the gap between a scanner producing a finding and an organisation patching in response. A pipeline is only as good as the remediation standing behind it, which is why the lifecycle figure in the first article of this unit closes the loop back to a rescan.
Real incident: WannaCry, 2017: a patch that arrived two months early
In May 2017, the WannaCry ransomware spread to more than two hundred thousand computers across over one hundred fifty countries in days, using EternalBlue, an exploit for a flaw in Microsoft's SMB protocol tracked as MS17-010. Microsoft had released the patch in March 2017, two months earlier. The machines WannaCry infected were, almost without exception, those the patch had not reached. The United Kingdom's National Health Service was among the hardest hit, with ambulances diverted and operations cancelled as systems went dark.
What this teaches: MS17-010 is precisely the finding a scan, run on a schedule and acted upon, would have flagged as critical on every unpatched host, months before WannaCry used it. As with Equifax, the technology did its job; the remediation did not. An assessment workflow earns its keep only when a human or a process reliably acts on what it reports.
Check your understanding
Question 1: Which two steps of the automated vulnerability assessment algorithm are pure data-shaping, needing no live tool connection, and which four need one?
Step 5 (assemble the report) and step 6 (write it as JSON) are pure data-shaping, operating only on data already held in memory. Steps 1 to 4, launching the scan, waiting for it, retrieving findings and running a targeted module, all need a live connection to Nessus or Metasploit.
Question 2: Explain why a JSON report is easier to feed into another system than a formatted document.
A formatted document, a PDF or a Word file, is built for a person to read on screen, and extracting specific values from it programmatically is unreliable. JSON is structured data with named fields a program can read directly, so a dashboard, a ticketing system or a comparison script can consume it without any parsing guesswork.
Question 3: In both the Equifax and WannaCry cases, the scanning technology was capable of finding the flaw. What actually failed, and how does the lifecycle figure from the first article of this unit address it?
In both cases the finding existed and the patch was available; what failed was the organisation acting on it, the remediation step. The lifecycle figure addresses this by explicitly including remediate and rescan as stages after report, not leaving the pipeline to end once a report is produced, so the loop back to confirming a fix is part of the process, not an afterthought.
Key takeaway
run_assessment() turns four live tool calls and two pure data operations into one pipeline, and its deliverable, structured JSON, is built for the next system to act on directly. But Equifax and WannaCry both show the same truth: a finding nobody acts on protects nobody. The loop must close on remediation.

