Skip to main content

nessus attestor

Ingests a Tenable Nessus .nessus XML report from the attestation products and emits a digest-pinned summary of hosts scanned, findings bucketed by severity, and CVEs referenced by critical/high findings.

Namenessus
Predicate typehttps://aflock.ai/attestations/nessus/v0.1
Lifecyclepostproduct
Default binary?No — builder opt-in only

What it captures​

The attestor walks ctx.Products() looking for files whose path ends in .nessus, verifies the file digest matches the product digest already recorded by the attestation context, then XML-decodes the NessusClientData_v2 document. The predicate records three top-level json-tagged fields:

  • reportFile — path of the .nessus file that was ingested.
  • reportDigestSet — the digest set carried by the matching product (used as the integrity anchor; the on-disk file is rejected if its digest does not match).
  • scanSummary — a Summary object containing:
    • totalHosts — count of <ReportHost> elements across all <Report> elements.
    • vulnerabilities — a SeverityCounts object with integer fields critical, high, medium, low, info (mapped from Nessus numeric severity 4/3/2/1/0; anything outside 1-4 falls into info).
    • topCVEs — deduplicated list of CVE IDs that appeared on any finding with severity High or Critical.

Per-finding raw data (plugin ID, plugin name, full CVE list, per-host item lists) is parsed from the XML but is not preserved in the predicate — only the aggregated counts and the critical/high CVE set survive into the attestation.

Subjects​

The attestor implements attestation.Subjecter and emits SHA-256 digested subjects:

  • nessus:host:<host-name> for every <ReportHost name="..."> encountered.
  • cve:<CVE-ID> for every CVE referenced by a finding whose severity is High (3) or Critical (4). Medium/Low/Info findings do not produce CVE subjects.

When to use​

Add this attestor to a custom cilock build when Nessus is your authoritative vulnerability scanner and you want a tamper-evident record of the scan summary attached to a release. The CVE subjects make the attestation joinable against vex statements and other CVE-keyed evidence.

Flags​

None. The attestor takes no configuration; it discovers the .nessus file by scanning the product set.

Output shape​

{
"reportFile": "out/scan-2026-05.nessus",
"reportDigestSet": {
"sha256": "..."
},
"scanSummary": {
"totalHosts": 12,
"vulnerabilities": {
"critical": 2,
"high": 7,
"medium": 15,
"low": 4,
"info": 88
},
"topCVEs": [
"CVE-2024-12345",
"CVE-2024-67890"
]
}
}

Gotchas​

  • .nessus XML only. The source matches strictly on the .nessus suffix and xml.Unmarshals a NessusClientData_v2 document. JSON exports, .csv, and .html reports are ignored.
  • Must be a product. The file has to be present in ctx.Products() — typically because an earlier step (or --attestor-product-include-glob) added it. If no .nessus file is in the product set the attestor returns no .nessus file found in products and fails the step.
  • Digest gate. If the on-disk file's digest does not equal the product digest already recorded, that file is silently skipped (debug-logged) and the attestor falls through to the next candidate.
  • Lossy summary. Plugin IDs, plugin names, and CVEs from Medium/Low/Info findings are parsed but discarded. If you need the full finding list, attach the raw .nessus file as a product as well — the digest in reportDigestSet lets verifiers fetch and re-parse it.
  • First match wins. Iteration order over ctx.Products() is map order; if multiple .nessus files are present, only the first one whose digest matches is recorded.

CLI example​

See the constraint summary + reproduction recipe at https://github.com/aflock-ai/attestor-compliance-examples/tree/main/35-nessus. This attestor is currently blocked or doc-only — the linked example explains why and shows the recipe to validate once the constraint is removed.

See also​