Appearance
Docker
A small Alpine image bundles the full recon toolchain so you can run scans and generate reports without installing nmap, bash, jq, and the rest on the host, and so you can run a versioned image instead of building from source.
- Base:
alpine:3.21, single stage (netvuln-tool has no compiled dependencies, so there is nothing to build). - Platforms:
linux/amd64andlinux/arm64, both covered bydocker buildx build --platform linux/amd64,linux/arm64, so you can build multi-arch locally for ARM edge devices as well as x86 hosts. - Contents: the whole source tree (
netvuln/ scripts/ lib/ templates/ assets/) plus the runtime tools listed below. The PythonnetvulnCLI drives the bash modules, which it resolves relative to the repo root, so a bare pip wheel would not work; the tree ships intact. - Entry point: the
netvulnCLI (recon,scan,upload,push,diff,status,daemon). - User: non-root (
netvuln).
Bundled tools
Required core: python3, bash, coreutils, gawk, grep, sed, jq, nmap + nmap-scripts (NSE).
Full recon: bind-tools (dig/host), whois, openssl, samba-client (smbclient), net-snmp-tools (snmpwalk/snmpget), curl, ca-certificates, tzdata.
Deliberately excluded: wkhtmltopdf (PDF export is broken on Alpine/musl; HTML reports are unaffected) and mail/sendmail (optional email delivery). If you need PDF export or email, run from a glibc-based host install instead (see Installation).
Build
From the repo root:
bash
docker build -t netvuln-tool:dev .A plain docker build targets your host's native architecture. docker buildx supports both linux/amd64 and linux/arm64, so to build locally for a specific target (for example an amd64 image from an Apple Silicon Mac), pass --platform explicitly:
bash
docker buildx build --platform linux/amd64 -t netvuln-tool:dev --load .Check the size:
bash
docker images netvuln-tool:devRun
Show CLI help (default command):
bash
docker run --rm netvuln-tool:dev --helpRun a recon scan. Scan sessions and generated reports land in /opt/netvuln-tool/sessions inside the container, so mount a volume to keep them:
bash
docker run --rm \
--network host \
-v "$PWD/out:/opt/netvuln-tool/sessions" \
netvuln-tool:dev recon -t 192.0.2.0/24--network host gives the container the host's network interfaces so it can see and scan the LAN. The default bridge network NATs the container onto its own subnet (for example 172.17.0.0/16), out of reach of your real targets, so for anything other than scanning the container host itself, use --network host.
Docker Desktop networking
--network host is a Linux Docker feature. On Docker Desktop (macOS/Windows) "host" is the Linux VM, not your laptop's LAN. Run scans from a Linux host (the fleet) for real LAN reach. Only scan networks and hosts you are authorized to assess.
Scan privileges: works out of the box (no --cap-add)
Privileged nmap phases (SYN scan, -O OS detection, -sU UDP for SNMP, and raw-socket host discovery) need raw sockets. This image runs as the non-root netvuln user, and there is a subtlety that trips up most containerized nmap setups:
Adding a capability to the container (
--cap-add=NET_RAW) puts it in the bounding set, but that is not effective for a non-root process. And nmap decides "am I privileged?" fromeuid==0, so it does not automatically use a capability even when one is present.
The image handles both halves so you do not have to:
- File capability on nmap:
setcap cap_net_raw+eip /usr/bin/nmap(baked at build time).NET_RAWis in Docker's default capability set, so the non-root user gets effective raw sockets with a plaindocker run, no--cap-addrequired. NMAP_PRIVILEGED=1(baked env): tells nmap to use raw scans despiteeuid != 0; the file capability makes that actually succeed.
Result: docker run --network host netvuln-tool:<v> recon -t <lan> performs full privileged scans as the non-root user, with no capability flags.
Capability caveats
- Do not
--cap-dropNET_RAW. The file capability carries the effective bit, so ifNET_RAWis removed from the bounding set the kernel refuses toexecnmap at all (Operation not permitted). Docker grantsNET_RAWby default, so this only bites if you deliberately drop it. If you must scan with all capabilities dropped, use a host install instead. - A few exotic nmap features (for example
--send-ethon some interfaces) also wantNET_ADMIN, which is not a Docker default. Add it only if you hit such a case:--cap-add=NET_ADMIN. It is intentionally not baked into the nmap file caps, as doing so would breakexecunder Docker's default cap set. --user rootremains the blunt fallback if capabilities are unavailable in your environment.
One command with Compose
docker-compose.yml wires up the frictionless path (network_mode: host, the sessions volume, and the image tag), so a scan is a single command:
bash
docker compose run --rm scan recon -t 192.168.1.0/24
# pin a version instead of :latest
IMAGE_TAG=v4.3.3 docker compose run --rm scan recon -t 10.0.0.0/24Reports and session data land in ./out. Build the image locally by uncommenting build: . in the compose file. If Bullium has provided a prebuilt image through a licensed registry (<registry-host>/netvuln-tool), reference that tag instead.
Portal upload / license
Portal upload, push, CVE lookup, and license validation use curl over HTTPS. Pass the config and license via environment or a mounted config file, for example:
bash
docker run --rm \
-e NV_API_KEY="$NV_API_KEY" \
-v "$PWD/report_config.conf:/opt/netvuln-tool/report_config.conf:ro" \
netvuln-tool:dev upload -c report_config.conf --latestThe license soft gate reads ~/.netvuln/license.key (that is, /home/netvuln/.netvuln/license.key) or the NV_API_KEY / NV_LICENSE_KEY environment variables. It never blocks core scanning. See License Provisioning.
Bash entry points
The bash pipeline is still available directly if you prefer it over the Python CLI:
bash
docker run --rm netvuln-tool:dev bash scripts/vulnscan_recon.sh -t 192.0.2.10Smoke test
tests/docker_smoke.sh builds nothing; it exercises an already-built image and asserts the required tools are present and netvuln --help runs:
bash
tests/docker_smoke.sh netvuln-tool:devSee also
- Installation: host install (
install.sh) and developer setup (setup.sh). - Raspberry Pi: running the container or a host install on ARM edge devices.
- License Provisioning: key formats, tiers, and the soft gate.
- Daemon Troubleshooting: failure modes for container scans (LAN reach, raw-socket capability, portal upload) alongside the systemd daemon path.
