Skip to content

Configuration ​

Environment variables ​

Copy .env.example to .env and adjust as needed.

API ​

VariableDefaultDescription
DEBUGfalseEnable debug mode (verbose errors, auto-reload)
LOG_LEVELINFOLog level: DEBUG, INFO, WARNING, ERROR
DOCKER_NETWORKscanner-netDocker network name used to reach scanner sidecars
ALLOWED_DOMAINSexample.comComma-separated scope rules; scans of other targets are refused
WEB_DIST_DIRapps/web/distDirectory of the built web UI served under /ui

Scope (ALLOWED_DOMAINS) ​

POST /api/scans/start and the web UI only accept targets matching a rule:

RuleAllows
example.comexample.com and every subdomain
*.example.comsubdomains only, not example.com itself
localhostlocalhost on any port

Only scan sites you own or have written permission to test. Restart the API after changing the rules. The UI's Settings screen lists the active rules and can check a target against them.

Security ​

VariableDefaultDescription
API_KEY(empty)Shared secret required in the X-API-Key header (or the api_key query parameter, for downloads and the log stream) on every endpoint except /api/health, /api/ready and the web UI files. When empty, the API is unauthenticated (a warning is logged at startup) — only acceptable on localhost. The web UI asks for the key in Réglages and keeps it in the browser.
WEB_CHECK_CLI_API_KEY(empty)Key sent by the web-check CLI; must match API_KEY.
API_BIND127.0.0.1Host interface the API port is published on. Only switch to 0.0.0.0 with API_KEY set.
ALLOWED_DOMAINSexample.comComma-separated allowlist. Every scan target must be one of these domains or a subdomain of one.
ALLOW_PRIVATE_TARGETSfalseAllow targets that are, or resolve to, private/loopback/link-local IPs, and single-label hostnames. Lab use only.
CORS_ORIGINS(empty)Comma-separated allowed origins. Empty disables CORS.
ZAP_API_KEYrequiredKey protecting the internal ZAP daemon API. docker compose refuses to start without it (openssl rand -hex 32).

Scan target validation ​

Before any scanner runs, the API rejects (HTTP 400) targets that:

  • do not use http:// or https:// (bare domains are accepted on /api/quick/dns, /api/quick/dns-enum and /api/deep/sslyze; /api/scans/start requires the scheme and answers 403 for targets outside the scope);
  • are localhost, end in .local, .internal, .localhost, .lan or .home.arpa, or are single-label names such as the zap / nuclei containers;
  • are non-public IP literals (private, loopback, link-local such as 169.254.169.254, reserved…);
  • are not covered by ALLOWED_DOMAINS;
  • resolve to a non-public IP address.

The last two IP-based rules are lifted by ALLOW_PRIVATE_TARGETS=true.

Ports ​

VariableDefaultDescription
API_PORT8000Host port for the FastAPI server (the container always listens on 8000)

Docker Compose profiles ​

ProfileServices started
(none)api, zap, nuclei, nikto
tools+ ffuf (directory fuzzer)

Example:

bash
# API + scanners + fuzzer
docker compose --profile tools up -d

Scanner configuration ​

ZAP ​

ZAP runs in daemon mode with its REST API protected by ZAP_API_KEY. Scan output is written to ./outputs/. The API connects to ZAP via http://zap:8090 on the Docker network (ZAP_HOST / ZAP_PORT).

Nuclei ​

Nuclei templates are stored in the nuclei-templates Docker volume and persist between restarts. The container stays idle until the API dispatches a scan command.

Nikto ​

Nikto runs in on-demand mode (idle container). The API calls nikto via docker exec or the internal Docker socket when a scan is triggered.

Wordlists (FFuf) ​

Custom wordlists go in apps/config/wordlists/. They are mounted at /wordlists inside the ffuf container.

Release configuration ​

Release Please is configured in .github/release/release-please-config.json (Python release type). The version is tracked in .github/release/.release-please-manifest.json.