Skip to content

Scan a target

A scan is three decisions: what to point at, which templates to run, and what to write out. This guide works through each against a target on your own machine, and calls out the flags whose behaviour does not match their --help text.

flowchart TB
    TP["templates on disk:<br/>local, user, system"] --> FI["filter by id, tag, severity,<br/>or language, then exclude"]
    SC["--scope: URL, host,<br/>domain, CIDR, @file"] --> TG["the targets to hit"]
    FI --> RUN["every selected template runs<br/>against every target"]
    TG --> RUN
    RUN --> OUT["scan-results.json<br/>and any other format"]
    RUN --> EC["an exit code"]

    class OUT,EC emphasis

Two servers, so scope selection has something to select between.

  1. Serve two directories, each with an exposed listing.

    Terminal window
    mkdir -p cxg-scan/a/data cxg-scan/b/data
    cd cxg-scan
    echo x > a/data/export.csv
    echo y > b/data/export.csv
    (cd a && python3 -m http.server 8000 --bind 127.0.0.1 &)
    (cd b && python3 -m http.server 8001 --bind 127.0.0.1 &)
  2. Confirm both answer.

    Terminal window
    curl -s -o /dev/null -w '8000 %{http_code}\n' http://127.0.0.1:8000/
    curl -s -o /dev/null -w '8001 %{http_code}\n' http://127.0.0.1:8001/
    8000 200
    8001 200

--scope is one flag that reads several shapes. A single URL is the simplest:

Terminal window
cxg scan --scope http://127.0.0.1:8000 --templates directory-listing-common-paths

A comma-separated list scans each entry:

Terminal window
cxg scan --scope http://127.0.0.1:8000,http://127.0.0.1:8001 \
--templates directory-listing-common-paths
Targets Scanned: 2
...
MEDIUM: 2
TOTAL: 2

For more than a couple of targets, put one per line in a file and pass it with @:

Terminal window
printf 'http://127.0.0.1:8000\nhttp://127.0.0.1:8001\n' > targets.txt
cxg scan --scope @targets.txt --templates directory-listing-common-paths
Targets Scanned: 2

--scope also accepts bare hosts, domains, and CIDR blocks like 192.168.1.0/24. For those, cxg scans each template’s own default ports.

Running one template by ID is the tightest scope, and what the examples above use. To run a set, filter instead.

By tag:

Terminal window
cxg scan --scope http://127.0.0.1:8000 --tags exposure

By severity, one value or the flag repeated:

Terminal window
cxg scan --scope http://127.0.0.1:8000 --severity high
cxg scan --scope http://127.0.0.1:8000 --severity high --severity critical

--severity selects which templates run. It does not change the severity each finding reports. See reading a scan.

To drop a specific template from a filtered run, name it in full:

Terminal window
cxg scan --scope http://127.0.0.1:8000 --tags exposure \
--exclude-templates directory-listing-common-paths
TOTAL: 0

--output sets the basename; --output-format sets one or more formats.

Terminal window
cxg scan --scope http://127.0.0.1:8000 --templates directory-listing-common-paths \
--output scan --output-format json,sarif,html,markdown,csv

That writes scan.json, scan.sarif, scan.html, scan.markdown, and scan.csv from one run. Pick by consumer:

Format For
json Automation. The full finding, evidence included. The default.
sarif CI code-scanning: GitHub Advanced Security, VS Code.
csv A spreadsheet: one row per finding, no evidence body.
html A human reading a report.
markdown Dropping into a doc or a ticket.

The extension you type is replaced by the format’s own, so --output report.txt --output-format json writes report.json.

In a pipeline, the exit status matters as much as the file:

Situation Exit
Scan ran, with findings, with none, or against a dead port 0
A template ID or filter matched nothing to run 1

A scan that reaches an unresponsive target still exits 0 with TOTAL: 0. A non-zero exit here means cxg could not assemble a run, not that the target is clean, so do not treat 0 as “secure”. Add -v to see per-template warnings.

Terminal window
kill %1 %2 2>/dev/null
cd ..
rm -rf cxg-scan
  • Tune the load. --rate-limit, --parallel-targets, and --parallel-templates control how hard a scan hits a target. --safe drops the checks that can disrupt a production system.
  • Pass context to a template. --context '{"param_name":"id"}' feeds JSON to templates that need parameters. Many auth-class templates report an INFO line telling you exactly which context keys they want.