CVE matching, MITRE ATT&CK technique annotations, and composite risk scoring — with exploit-first ranking so the findings that are being exploited come first. Then send the result: one command renders a finished scan into a self-contained, print-ready HTML report that opens with no external network reference.
A scan ends with a directory of artifacts. An engagement ends with something a client reads.
nsauditor-ai report closes that gap: point it at a finished run and it renders an
executive HTML report — one self-contained, print-ready file that
opens with no external network reference of any kind. It survives an email
attachment, a laptop with no connectivity, and a reviewer’s locked-down browser.
Add --brand when the report goes out under your own name and the cover page carries it.
--format jira writes a Jira-importer CSV instead, so a findings list
becomes a backlog. ⚠️ That CSV is written for Jira’s own CSV importer — the field
mapping is done inside Jira, and this is not a live-instance integration we have verified.
brand.jsonEvery field is optional. Omit the file and the report renders unbranded under its default title.
// brand.json — put it next to your logo { "title": "Q3 External Perimeter Review", "companyName": "Acme Manufacturing GmbH", "preparedBy": "J. Rivera, Security Consulting LLC", "contact": "security@example.com", "logoPath": "acme-logo.png" }
title replaces the headline;
companyName is who the report is
for; preparedBy is who prepared it.
logoPath is a local PNG or JPEG,
resolved next to the brand file and embedded into the HTML as a data URI.
That logo rule is strict on purpose, and every part of it protects the same promise —
that the file opens with no external network reference. A URL is refused and never fetched:
a remote logo is egress at render time and a tracking pixel every time your client opens the report.
SVG is refused, because SVG is markup that can carry a script and break the no-script guarantee from
inside the image. The path may not escape the brand file’s own directory, checked as typed and
again after symlinks resolve. The cap is 2 MB, and the format is read from the file’s
magic bytes rather than its extension — renaming an SVG to
.png does not get it past the check.
A brand file that cannot be read, is not valid JSON, or whose logo is refused is a fatal error
and no report is written: a flag you passed is never silently dropped, because that is how a report goes
out unbranded without anyone noticing.
A report that quietly skips a container reads exactly like a report that had nothing to skip. So every report carries a container census: where finding-like records sit in a place the report does not read, that place is named and counted on the page. Silence is disclosed — never rendered as absence.
report is a Pro capability and is included in Enterprise. It produces no PDF: the
HTML is print-ready, and your browser prints it when a PDF is what the client asked for.
# 1 · a normal scan, as always nsauditor-ai scan --host 192.168.1.0/24 --plugins all # 2 · turn that finished run into the document you send nsauditor-ai report --from out/192.168.1.0_<timestamp> --format executive # or the same run as a Jira-importer CSV — you map the fields in Jira nsauditor-ai report --from out/192.168.1.0_<timestamp> --format jira
Requires nsauditor-ai v0.2.49+ alongside your Pro or Enterprise licence. The report reads a run that
already finished — it never re-scans, and it never reaches the network to render.
A consulting firm audits a client’s gateway at 192.168.1.1
and has to hand back something the client can actually read. Six steps — the same six on a
/24, on a cloud account, or on a hundred hosts.
nsauditor-ai license --status # On Community, `report` refuses at exit 2 and writes no file: # "`report` is a Pro capability. Your licence resolves to tier "community". # No file has been written." # The other precondition is not a command: signed authorization for the # target range. The scope on that letter is what the report cover should match.
~/consulting/brand/ ├── brand.json └── acme-logo.png # The logo must sit inside this directory and be named by a plain relative # path. Checked as typed, and again after symlinks resolve.
nsauditor-ai scan --host 192.168.1.1 --plugins all \ --compliance all --out ~/engagements/acme-2026-09/ # Writes a run record `scan_run_<id>.json` at the root and a timestamped # evidence folder beside it, with a .sha256 sidecar per artifact. # One --out per engagement. `report` picks the NEWEST run in a directory and # only refuses on an exact start-time tie — so a directory holding two # engagements can render the wrong one silently. Name the run when in doubt.
# --run names YOUR OWN run — the id your scan printed. It is the <id> in the # scan_run_<id>.json at the --out root. The one below is an example. nsauditor-ai report --from ~/engagements/acme-2026-09/ \ --run 20260904T184352Z-d9d796 \ --format executive \ --brand ~/consulting/brand/brand.json \ --out ~/engagements/acme-2026-09/Acme_192.168.1.1_executive.html [report] runId 20260904T184352Z-d9d796 · started 2026-09-04T18:43:52.970Z [report] wrote ~/engagements/acme-2026-09/Acme_192.168.1.1_executive.html ✓ exit 0 # Without --out it writes report_<runId>.html beside the run record — inside # your evidence tree, named after an id no client recognises. Name it for them.
nsauditor-ai report --from ~/engagements/acme-2026-09/ \ --run 20260904T184352Z-d9d796 \ --format jira \ --out ~/engagements/acme-2026-09/Acme_192.168.1.1_findings.csv # Summary,Description,Priority,Labels,External ID — one row per finding. # Passing controls are filtered out; nobody wants a ticket for a PASS. # External ID is stable, so a re-test maps back to the same rows. # ⚠ The column-to-field mapping is done inside Jira's own CSV importer. # That is not a live-instance integration we have verified.
# (a) A container census runs on load. If finding-like records sit somewhere # the report does not read, you are told — by container, with a count: [report] WARNING: N finding-like object(s) on host <h> live in `<container>`, which this report does not read. They are NOT in the output. # (b) Coverage caveats print too, and each is independent of the other: [report] coverage: partial — N of M not scanned [report] coverage: incomplete — the run did not record completion # (c) Then open it. A self-contained file with no external reference looks # the same offline as online — which is the first thing the client's own # security team will check.
Send the HTML on its own. It is one file — no asset folder,
no stylesheet to lose, and it prints from the browser when the client asked for a PDF. What you
keep is the evidence directory and its .sha256
sidecars: that is what lets you show, months later, that the report you sent came from that scan.
Re-rendering the same --run overwrites
the same filename rather than accumulating copies, so there is never a question of which one is current.
Version-based CVE matching is just the start. Every finding is scored — CVSS weighted by verification status, with an uplift for findings carrying an initial-access technique — and the queue is then ordered exploit-first. Findings are emitted unverified — you adjudicate what stays, not the scanner.
Severity ranks how bad a vulnerability would be if it were exploited. It cannot tell you whether anyone is exploiting it. Pro closes that gap at scan time: every finding carrying a CVE is joined by CVE ID against a local CISA KEV catalog and a local FIRST EPSS scores file, then banded and reordered exploit-first.
The justification travels with the finding — the KEV flag, the EPSS score with its percentile, the CVE ids that matched, and the store’s own as-of date. Your ranking is always something you can date and defend. Both catalogs are free, public and operator-supplied: point Pro at files you control and the join runs entirely on your machine.
Your existing riskScore does not move — exploitPriority is a new axis
beside it. And this is enrichment, not detection: it reorders what the scanner already found.
See Pro end to end — recorded on the 0.42 line:
The Pro overview covers exploit-first triage with CISA KEV and FIRST EPSS — free public feeds you download and point Pro at, failing closed when stale — offline-first CVE matching from detected service versions, findings emitted unverified for you to adjudicate, AI analysis on your own API keys, and risk-ranked reports built for one-click print to PDF.
# 1 · Download the feeds (public, no account needed for either) mkdir -p ~/.nsauditor/feeds curl -fsSL https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json -o ~/.nsauditor/feeds/kev.json curl -fsSL https://epss.empiricalsecurity.com/epss_scores-current.csv.gz | gunzip > ~/.nsauditor/feeds/epss.csv # 2 · Point the scanner at them (add both lines to your shell profile to persist) export NSAUDITOR_EXPLOIT_KEV_STORE=~/.nsauditor/feeds/kev.json export NSAUDITOR_EXPLOIT_EPSS_STORE=~/.nsauditor/feeds/epss.csv # 3 · Scan as usual — findings that carry CVEs arrive banded and ordered exploit-first nsauditor-ai scan --host 192.168.1.0/24 --plugins all
The stores are the feeds' own formats — no conversion step. Refresh KEV within 14 days and EPSS within 10 (a cron works);
a stale or unparseable store fails closed and the scan says so — it never silently reports
“not exploited”. Setting these outside a shell? ~ expands only in a shell —
in a --env file or Claude Desktop’s MCP env config, write the absolute path (e.g.
/Users/you/.nsauditor/feeds/kev.json); a path the scanner cannot read is reported as no-store, never as
“not exploited”. Full walk-through: getting-started → exploit intelligence.
Exploit intelligence is a Pro-tier capability and is off until you configure it. Enterprise includes Pro.
Pro sharpens the queue. Enterprise turns the result into something an assessor reads — 29 Enterprise plugins, 28 of them cloud auditors across AWS, Azure and GCP, and one read-only scan mapped to eight frameworks with an explicit out-of-scope column.
It is also where suppression lives — and suppression is an Enterprise capability, not a Pro one. Enterprise adds a suppression workflow for the compliance report: accepted-risk and false-positive records keyed on source and title pattern, approved with an approver’s signature, renewable on a cadence, and read by the compliance engine — which Pro does not run, so a suppression has no effect on a Pro report. The Enterprise compliance engine gives each decision an owner, a rationale, a date and an expiry inside the evidence pack — and as of EE 0.36.0 the report checks that approval’s signature against the key material the approver’s registry entry declares, rather than repeating what the record says about itself. A missing verdict reads not checked and never failed.
Isolated networks are Enterprise too: the offline install walkthrough — carry the package and the CVE data in, verify checksums, then import the feed — now lives on the Enterprise page.
None of that is part of a Pro licence. If your buyer is an auditor rather than a remediation queue, that is the tier to look at.
CISA KEV + FIRST EPSS joined by CVE ID at scan time, banded KNOWN_EXPLOITED / ELEVATED / BASELINE, queue ordered exploit-first. Operator-supplied catalogs; the join runs locally. See how →
Auto-generated CPEs from detected services matched against the NVD feed — offline-first: your local NVD store answers first, and on a miss the public NVD API is queried unless NSAUDITOR_OFFLINE_ONLY=1, which turns the miss into a coverage-gap finding instead of a request. Know which CVEs affect each host before writing a single line of your report.
Every finding is annotated with the ATT&CK techniques it relates to, with kill-chain context. Compliance teams love it. Clients understand it. Takes zero extra effort on your part.
Four analysis agents run concurrently on Pro — Auth, Crypto, Config and Service. The Exposure agent is Enterprise. Each produces structured findings for its category, then feeds the risk engine.
CVSS weighted down while a finding is unverified — with a 15% uplift for findings carrying an initial-access ATT&CK technique. Reports render severity-grouped, highest-impact first.
report --from <run> --format executive renders a finished scan into one self-contained, print-ready HTML file that opens with no external network reference — optional cover-page branding via --brand. --format jira writes a Jira-importer CSV. Every scan still writes HTML, JSON and Markdown as before. See how →
Same OpenAI / Claude / Ollama providers you use in CE — but Pro injects CVE matches, MITRE techniques, and risk scores into every prompt. Vastly better output.
Unlimited scan history in SQLite. CVE-level delta detection — new vulnerabilities since last scan, not just host diffs. Risk trend analysis (improving / degrading / stable).
Configurable profiles (strict / moderate / minimal), additional patterns for AWS keys, DB connection strings, and JWTs. Full redaction audit log for compliance.
The MCP server registers seven tools and lists all seven to every client; the licence gate is applied when a tool is called. Pro unlocks probe_service and get_vulnerabilities on top of the three every tier can run.
report --from <run> → executive HTML or Jira-importer CSV
list_plugins completes the every-tier set;
scan_cloud and
get_findings are Enterprise. Seven tools in total — all seven are listed to every client, and the licence is checked when one is called.
Start the MCP server with nsauditor-ai-mcp — works with Claude Desktop, Cursor, and any MCP-compatible AI assistant.
# @nsasoft/nsauditor-ai-ee is a private (restricted) package. # Use the npm read-token delivered with your license email. npm config set //registry.npmjs.org/:_authToken npm_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Or, project-scoped, in an .npmrc file echo "//registry.npmjs.org/:_authToken=npm_xxxx..." >> ~/.npmrc
# One line — installs both the CE platform and the Pro package npm install -g nsauditor-ai @nsasoft/nsauditor-ai-ee
# The CE license installer verifies the JWT signature before persisting # and stores the key in macOS Keychain (or ~/.nsauditor/.env mode 0600 elsewhere). nsauditor-ai license install pro_eyJhbGciOiJFUzI1NiIs... ✓ Pro license installed Stored at: macOS Keychain (service=nsauditor-ai) Org: you@example.com Expires: 2027-04-29 # Verify nsauditor-ai license --status ✓ Pro license active
nsauditor-ai scan --host 192.168.1.0/24 --plugins all # View your AI report in browser open out/192.168.1.0_*/scan_response_ai.html # macOS xdg-open out/192.168.1.0_*/scan_response_ai.html # Linux # Each scan writes HTML, JSON, and Markdown reports — print the HTML to PDF for clients nsauditor-ai scan --host 10.0.0.0/24 --plugins all open out/10.0.0.0_*/scan_response_ai.html # print → PDF # And turn that finished run into the one file you send the client nsauditor-ai report --from out/10.0.0.0_<timestamp> --format executive
Subscribe directly to unlock CVE matching, MITRE ATT&CK annotations,
risk scoring, and parallel analysis agents — and the report subcommand that turns a
finished scan into one self-contained HTML file you can send, or a Jira-importer CSV.
Cancel anytime; an annual plan stays active to the end of its paid year, then reverts to
Community Edition with no data lost.