Share an Nmap scan report

Nmap's XML output is machine-readable and unreadable by people; the terminal output is readable and unpasteable. The bridge has shipped with Nmap for years and almost nobody uses it — nmap.xsl, which turns the XML into a clean HTML report with the host table, open ports, and detected service versions.

The reason nobody uses it is not the stylesheet. It is that the HTML has nowhere to go afterwards, and a network scan is the last artifact anyone wants to drop into a chat window.

Convert and publish

nmap -sV -oX scan.xml 10.0.0.0/24
xsltproc scan.xml -o scan.html

curl -fsS -X POST "https://commareports.com/api/v1/reports" \
  -H "Authorization: Bearer $COMMA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile html scan.html \
        --arg title "Perimeter scan — $(date +%Y-%m-%d)" \
        '{title: $title, html: $html, visibility: "private"}')"

Scan only what you are authorized to scan. Assuming that box is ticked, the sharing question is the one this page is about.

Set visibility first, not later. An open-port inventory with service versions is a starting point for an attacker. Create it private, then widen to your team, an email domain, or named reviewers. See the sharing model.

The findings that are not findings

Most of a recurring scan is noise you already understand — and understand again, from scratch, every quarter, because the explanation lived in a DM. Anchored comments fix exactly that:

  • "tcp/8443 — internal load balancer, expected."
  • "This host is decommissioned, DNS record is stale, ticket OPS-88."
  • "New since last scan. Nobody owns this. Escalating."

Each one attaches to the host it is about and survives the next scan, because revisions carry the threads forward. See commenting on HTML.

Recurring scans

curl -fsS -X PATCH "https://commareports.com/api/v1/reports/$REPORT_ID" \
  -H "Authorization: Bearer $COMMA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile html scan.html '{html: $html}')"

One report id per scope. The diff between two revisions answers the only question a recurring scan exists to answer: what is open now that was not open before. A scheduled routine can run it without anyone remembering to.

Limits

  • HTML body: 5 MB. A /16 with service detection will exceed it — split by subnet and publish one report per scope, which is how you would want to read it anyway.
  • Scripts run, sandboxed: allow-scripts, no allow-same-origin.
  • 60 requests/minute per token.

Try it

Comma is free — unlimited reports, unlimited commenters, unlimited revision history.

Publish a scan report →

Related