> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vigolium.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Native Scan & Stateless Scanning

> The native scan is Vigolium's deterministic, Go-based scanning pipeline, fast, modular, and AI-free. This page is a hands-on tour of running native scans from the CLI, with a focus on stateless scanning.

<Columns cols={2}>
  <Frame caption="Native Scan CLI">
    <img src="https://mintcdn.com/vigolium/NLZDE082IZ_kV-1b/images/vigolium-cli-native-scan.png?fit=max&auto=format&n=NLZDE082IZ_kV-1b&q=85&s=c219c83a174dc5093f8d23aaf573e30c" width="4336" height="2804" data-path="images/vigolium-cli-native-scan.png" />
  </Frame>

  <Frame caption="Native Scan CLI">
    <img src="https://mintcdn.com/vigolium/LhScJ9FgxQS8TSGT/images/vigolium-cli-native-scan-2.png?fit=max&auto=format&n=LhScJ9FgxQS8TSGT&q=85&s=5b2b14db63c8918716fdc917ab7ea6df" width="3824" height="2366" data-path="images/vigolium-cli-native-scan-2.png" />
  </Frame>
</Columns>

Use stateless scanning for CI/CD pipelines, scripting, AI-agent integration, and quick ad-hoc checks. For the conceptual deep-dive see [Scanning Modes Overview](/native-scan/scanning-modes-overview); for the full strategy reference see [Strategies](/native-scan/strategies).

## Stateless at a glance

| Command            | Persists to DB?               | Phases                  | Use it for                |
| ------------------ | ----------------------------- | ----------------------- | ------------------------- |
| `scan-url`         | No                            | none, direct module run | One URL, fast             |
| `scan-request`     | No                            | none, direct module run | A raw HTTP request / curl |
| `scan --stateless` | No (temp DB, discarded)       | full pipeline           | One-shot full scan        |
| `scan`             | Yes (`~/.vigolium/...sqlite`) | full pipeline           | Persistent projects       |

`scan-url` and `scan-request` never touch a database. `scan --stateless` creates a temporary SQLite database, runs every requested phase, exports results, and deletes the database on exit.

<Callout icon="circle-info" color="#3B82F6" iconType="regular">
  Pass `-o/--output` (with `--format`) when using `--stateless`, otherwise results are discarded along with the temporary database. Vigolium prints a warning if you forget. `--stateless` and `--db` are mutually exclusive.
</Callout>

## Scan a single URL, `scan-url`

```bash theme={null}
# Simplest possible scan
vigolium scan-url https://example.com/api/users?id=1

# JSON output for scripting
vigolium scan-url -j https://example.com/api/users?id=1
```

POST with a body and headers:

```bash theme={null}
vigolium scan-url \
  --method POST \
  --body '{"user":"admin","pass":"secret"}' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer tok123' \
  https://example.com/api/login
```

Scope the modules and skip work you don't need:

```bash theme={null}
# Only injection-class modules (fuzzy match on ID/name)
vigolium scan-url -m sqli -m xss "https://example.com/search?q=test"

# Filter by tag
vigolium scan-url --module-tag injection https://example.com/api/data

# Skip passive analysis and insertion-point fuzzing for the fastest result
vigolium scan-url --no-passive --no-insertion-points https://example.com/api/data
```

Run a discovery/spider phase *before* the scan (these promote `scan-url` to the full pipeline and require a database, pass `--db`):

```bash theme={null}
vigolium scan-url --discover --db /tmp/scan.sqlite https://example.com
```

## Scan a raw HTTP request, `scan-request`

```bash theme={null}
# From a file containing a raw HTTP request
vigolium scan-request -i request.txt

# From stdin
printf 'GET /api/users?id=1 HTTP/1.1\r\nHost: example.com\r\n\r\n' \
  | vigolium scan-request

# From a curl command (auto-detected)
echo "curl -X POST -d 'user=admin' https://example.com/login" \
  | vigolium scan-request
```

Override the host when the request file has only a path:

```bash theme={null}
vigolium scan-request -i request.txt --target https://staging.example.com
```

## Piping from stdin

Both `scan-url` and `scan-request` auto-detect the stdin format, plain URL, curl command, or raw HTTP request:

```bash theme={null}
# Plain URL
echo 'https://example.com/search?q=test' | vigolium scan-url

# Curl command
echo "curl -H 'Content-Type: application/json' -d '{\"id\":1}' https://example.com/api" \
  | vigolium scan-url

# Raw HTTP request
printf 'POST /api/login HTTP/1.1\r\nHost: example.com\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\nuser=admin&pass=secret' \
  | vigolium scan-request

# Scan whatever is on your clipboard (macOS)
pbpaste | vigolium scan-url -j
```

## Full stateless pipeline, `scan --stateless`

Run discovery, spidering, and dynamic-assessment with no persistent state. `--stateless` works on both `scan` and `run`:

```bash theme={null}
# Full pipeline, JSONL out, nothing left behind
vigolium scan --stateless -t https://example.com --format jsonl -o results

# Add content discovery, write both JSONL and HTML
vigolium scan --stateless -t https://example.com \
  --discover --format jsonl,html -o scan-output

# A single phase, statelessly
vigolium run dynamic-assessment --stateless -t https://example.com \
  --format jsonl -o results
```

Multiple targets from a file scan into one shared temporary database and export to a single unified output file by default:

```bash theme={null}
vigolium scan --stateless -T targets.txt --format jsonl -o results
# -> results.jsonl (all targets combined)
```

Add `--split-by-host` to instead scan each target in its own isolated temporary database and write a separate per-host output file (the filename is suffixed with the host so results don't overwrite):

```bash theme={null}
vigolium scan --stateless -T targets.txt --split-by-host --format jsonl -o results
# -> results-example.com.jsonl, results-test.example.com.jsonl, ...
```

## ⚡Scanning a huge list of targets in parallel

When you point Vigolium at a large target list, use `-P/--parallel N` to scan several hosts at once. Each target runs in its own isolated child process — so there is no cross-contamination between workers — and each child keeps its own `--concurrency`, meaning real in-flight requests are roughly `N × --concurrency`.

`-P` requires one of two output strategies so results never collide:

* **`--stateless --split-by-host`** — each target runs against its own temporary database and writes a separate per-host output file (`base-<host>.<ext>`). Nothing is persisted. Best for stateless, fire-and-forget batches.
* **`--db-isolate`** — each worker scans into a private temporary SQLite database, then merges its results into the shared `--db` (or the default DB) at the end. This lets many parallel scans share one database without write contention, and you export one unified report from the merged DB afterward.

```bash theme={null}
# Stateless fan-out: per-host JSONL + HTML files, 3 targets at a time
vigolium scan -T list-of-targets.txt -P 3 \
  --stateless --split-by-host \
  --format jsonl,html --output prefix-output \
  --fuzz-wordlist ~/Tools/contents/fast.txt

# Shared-DB fan-out: 4 targets at a time merged into one local.db, one unified output
vigolium scan -T list-of-targets.txt -P 4 \
  --db-isolate --db local.db \
  --format jsonl,html --output report \
  --fuzz-wordlist ~/Tools/contents/fast.txt
```

<Callout icon="circle-info" color="#3B82F6" iconType="regular">
  `--db-isolate` is SQLite-only and cannot be combined with `--stateless` (they are two different ways to avoid write contention). Pressing `Ctrl-C` during a `-P` batch is treated as an operator stop: un-started and cut-short targets are reported as "not scanned" rather than failures.
</Callout>

### Resuming an interrupted fan-out

A stateless parallel fan-out (`-S -T --split-by-host -P`) writes a tiny line-cursor manifest, `<output>.progress.json`, tracking the targets that completed cleanly. If the batch is interrupted (Ctrl-C, a crash, a CI timeout), re-run it with `--resume` to skip the finished targets and scan only the remainder — Vigolium also prints a copy-pasteable resume command on Ctrl-C/failure:

```bash theme={null}
# Original run
vigolium scan -T targets.txt -P 4 --stateless --split-by-host --format jsonl -o results

# Resume only the targets that didn't finish
vigolium scan -T targets.txt -P 4 --stateless --split-by-host --format jsonl -o results --resume
```

Run `vigolium scan --resume` bare — with no other flags — and it auto-discovers the `*.progress.json` in the current directory and relaunches the saved run from it (pass `-o <prefix>` to disambiguate when several manifests exist).

<Callout icon="circle-info" color="#3B82F6" iconType="regular">
  `--resume` currently applies only to the parallel fan-out (`-S -T --split-by-host -P > 1`). Resuming a plain sequential scan re-runs it in full.
</Callout>

## Stateless scans from other input sources

```bash theme={null}
# OpenAPI / Swagger spec
vigolium scan --stateless -i api.yaml -I openapi \
  -t https://api.example.com --format jsonl -o results

# Postman collection
vigolium scan --stateless -i collection.json -I postman \
  -t https://api.example.com --format jsonl -o results

# Burp Suite XML export
vigolium scan --stateless -i export.xml -I burpxml --format jsonl -o results

# HAR capture
vigolium scan --stateless -i traffic.har -I har --format jsonl -o results

# Nuclei JSONL
vigolium scan --stateless -i nuclei.jsonl -I nuclei --format jsonl -o results
```

## Tuning a scan

```bash theme={null}
# Speed knobs — defaults: -c 50, -r 100 req/s, --max-per-host 30, --timeout 15s
vigolium scan --stateless -t https://example.com \
  -c 100 -r 200 --max-per-host 10 --timeout 30s \
  --format jsonl -o results

# Strategy presets trade depth for speed
vigolium scan --stateless -t https://example.com --strategy lite -o r --format jsonl
vigolium scan --stateless -t https://example.com --strategy deep -o r --format jsonl

# Route everything through a proxy
vigolium scan --stateless -t https://example.com --proxy http://127.0.0.1:8080 \
  --format jsonl -o results

# Constrain how broadly scope is interpreted
vigolium scan --stateless -t https://example.com --scope-origin strict \
  --format jsonl -o results

# Include the full HTTP response body in findings (scan / run only)
vigolium scan --stateless -t https://example.com --include-response \
  --format jsonl -o results
```

## Authenticated stateless scans

Pass an inline session or a session file, both work in stateless mode:

```bash theme={null}
# Inline session: name:Header:value
vigolium scan --stateless -t https://example.com \
  --auth "admin:Cookie:session_id=abc123" \
  --format jsonl -o results

# Single session or multi-session bundle file (YAML or JSON)
vigolium scan --stateless -t https://example.com \
  --auth-file ./admin-session.yaml \
  --format jsonl -o results

# A static header is often enough for token auth
vigolium scan-url -H 'Authorization: Bearer token123' \
  https://example.com/api/me
```

See [Authenticated Scanning](/native-scan/authentication) for login flows, token extraction, and multi-session IDOR/BOLA testing.

## CI/CD integration

`--ci-output-format` forces clean JSONL with no banners or color codes, ideal for parsing in a pipeline:

```bash theme={null}
vigolium scan --stateless -t https://example.com \
  --ci-output-format -o findings
```

A minimal gate that fails the build when any finding is reported:

```bash theme={null}
vigolium scan --stateless -t "$TARGET" --ci-output-format -o findings
test ! -s findings.jsonl || { echo "Vulnerabilities found"; exit 1; }
```

See [CI/CD Integration](/guides/ci-cd-integration) for full pipeline examples.

## Output formats recap

| `--format`           | Output             | Notes                                                                             |
| -------------------- | ------------------ | --------------------------------------------------------------------------------- |
| `console`            | Terminal (default) | Colored, human-readable                                                           |
| `jsonl`              | `<o>.jsonl`        | One JSON object per line; `-j` is shorthand                                       |
| `html`               | `<o>.html`         | Interactive ag-grid report; requires `-o`                                         |
| `sqlite`             | `<o>.sqlite`       | Standalone DB dump (`VACUUM INTO`); requires `-S` + `-o`. Aliases `sqlite3`, `db` |
| `console,jsonl,html` | All of the above   | Comma-separate to combine                                                         |

For stateless runs, `-o` is the **base** path, Vigolium appends the correct extension per format and materializes every requested format from the temporary database before tearing it down.

## Next steps

* [Stateless Scanning Guide](/guides/stateless-scan), the extended recipe book.
* [Scanning Strategies](/native-scan/strategies), strategies, profiles, pace.
* [Native Scan: How It Works](/native-scan/how-it-works), the pipeline internals.
* [Scanner Modules Reference](/native-scan/modules-reference), every module.
* [Output & Reporting](/getting-started/output-and-reporting), formats and reports in depth.

<Callout icon="key" color="#8B5CF6" iconType="regular">
  **Oh dear, you actually read to the end.** Here's the secret the config file
  kept nudging you toward: by default every Vigolium request announces itself
  with a `Vigolium/<version>` User-Agent, so a friendly blue team can spot your
  authorized scan in their logs in seconds. Go full ninja only when you *mean*
  to be sneaky:

  ```bash theme={null}
  # Persist it in your config
  vigolium config set scanning_strategy.http.user_agent random

  # Or a one-off via env var (overrides the config value for that run)
  export VIGOLIUM_DEFAULT_UA=random
  ```
</Callout>
