This guide covers the source-checkout workflow for running Ravage against controlled, authorized targets.
Ravage is not a public-internet scanner. Use it only against systems you own or
are explicitly authorized to test. The active CLI is localhost-first: expose
the authorized app on 127.0.0.1 or localhost, then put that URL in the
brief.
Ravage takes an engagement brief, checks scope, runs tools, records evidence, and writes a report. You choose one of two normal workflows:
ravage scan: deterministic DAST. Use this first when you want a repeatable
baseline with no model spend.ravage attack: model-driven agent. Use this when you want the ai-web
agent to plan and choose tool actions.Both workflows write the same kind of run directory, so you can inspect, compare, and resume them the same way.
The brief is the user-facing configuration file. It should say what target is authorized, what behavior is allowed, and whether this is a broad assessment or a targeted retest.
For a normal web pentest, use a broad objective:
engagement_id: "99999999-9999-4999-8999-999999999999"
scope:
in_scope:
- "https://staging.example.test"
out_of_scope: []
roe:
max_rps: 5
no_destructive_actions: true
data_handling: "placeholders_only"
objectives:
- "web_application_assessment"
budget:
max_cost_usd: 5.0
max_runtime_min: 20
Use api_security_assessment when the target is primarily an API. Use
specific classes like xss, jwt, or sql_injection only for targeted
retests or lab runs. Clean XBEN runs should not include vulnerability-class
hints; let the agent derive hypotheses from the challenge description and live
target evidence.
This quickstart runs the local Acme lab and a deterministic scan. It does not call a model.
git clone https://github.com/duriantaco/ravage.git
cd ravage
scripts/bootstrap.sh
source .venv/bin/activate
ravage --version
ravage lab up ravage-acme-box --labs-dir examples/labs
ravage scan examples/labs/ravage-acme-box/brief.yaml \
--run-dir runs/quickstart-acme-scan \
--probe surface_map \
--report
python -m json.tool runs/quickstart-acme-scan/report.json | head -80
ravage audit verify runs/quickstart-acme-scan
ravage lab down ravage-acme-box --labs-dir examples/labs
Expected result: the run directory exists, report.json is present, and audit
verification prints audit verify OK.
Use the agent only after the scan workflow is working:
ravage attack examples/labs/ravage-acme-box/brief.yaml \
--model-profile local-ollama \
--model-tier mid \
--tool-runtime auto \
--memory off \
--max-turns 18
Use Python 3.12 and install the checkout:
cd ravage
scripts/bootstrap.sh
source .venv/bin/activate
Verify the CLI:
ravage --version
ravage init --target-url http://127.0.0.1:8080
ravage setup check --brief brief.yaml
If an old virtualenv entry point still imports orchestrator, rerun bootstrap.
It repairs stale .venv activation paths and reinstalls the editable checkout:
scripts/bootstrap.sh
For development runs before reinstalling, call the module directly:
PYTHONPATH=packages/ravage/src:packages/schemas/src \
.venv/bin/python -m ravage --help
Manual install equivalent, when you are not using bootstrap:
python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install "setuptools>=68" wheel
python -m pip install --no-build-isolation -e .
ravage --version
Ravage can run with host tools, Docker-backed tools, or auto mode. Auto mode uses host tools when available and falls back to the configured Docker image.
List supported tool binaries:
.venv/bin/ravage tools list
Check local and Docker availability:
.venv/bin/ravage tools check
Install or build supported external tools from the source checkout:
scripts/install_tools.sh --method docker --execute
.venv/bin/ravage tools check
Local labs are deliberately vulnerable. Keep them on localhost or an isolated private lab network.
docker compose -f examples/labs/ravage-acme-box/docker-compose.yml up --build
In another terminal, confirm the target is reachable:
curl -sS http://127.0.0.1:8080/
Use ravage scan when you want a reproducible run without model calls:
.venv/bin/ravage scan examples/labs/ravage-acme-box/brief.yaml \
--run-dir runs/acme-scan \
--tool-runtime auto
Useful options:
--probe NAME: run one deterministic probe; repeat for multiple probes.--all-probes: run the full in-tree deterministic probe catalog.--timeout-seconds N: cap probe runtime.--report: write a redacted report after the scan finishes.--json: print the final scan summary as JSON.Use ravage attack for the model-driven ai-web loop:
.venv/bin/ravage attack examples/labs/ravage-acme-box/brief.yaml \
--model-profile local-ollama \
--model-tier mid \
--tool-runtime auto \
--memory off \
--max-turns 18
For hosted routes, set the provider key and opt into paid model use:
OPENAI_API_KEY=... \
.venv/bin/ravage attack examples/labs/ravage-acme-box/brief.yaml \
--model-profile hosted-openai \
--model-tier low \
--tool-runtime auto \
--memory off \
--allow-paid-models
Attack run directories are stateful. Leave --run-dir unset for normal new
runs so Ravage creates a timestamped directory. If you set --run-dir yourself,
use a new path for each fresh attack. Reusing an old attack workspace is blocked
unless you pass --resume.
Important options:
--agent-mode hybrid: normal mode with runtime recommendations and
deterministic proof support.--agent-mode ctf-free-roam: benchmark/CTF mode that encourages bounded
autonomous exploration.--allow-degraded: continue when optional model/tool checks are degraded.--allow-paid-models: acknowledge paid hosted model use.--memory off: keep the public CLI memory path disabled.--report: run the final report-writing agent after the attack.--resume: continue from an existing run workspace.Resume an attack by pointing at the same run directory and passing --resume:
.venv/bin/ravage attack examples/labs/ravage-acme-box/brief.yaml \
--run-dir runs/acme-attack \
--resume \
--memory off
Open the observer for an existing run:
.venv/bin/ravage observe runs/acme-attack
The observer follows an existing run directory. Start it in a separate terminal after the run directory exists.
Attack and scan runs write a consistent run shape:
report.json: machine-readable summary and findings.report.html: rendered report when available.audit.db: append-only audit rows with hash-chain verification.workspace/events.jsonl: structured runtime events.workspace/transcript.jsonl: model/tool transcript for agent runs.workspace/artifacts/: large model or tool outputs.agent.stdout or scan.stdout: process output.Verify the audit hash chain:
.venv/bin/ravage audit verify runs/acme-attack
A successful run is not just “the process exited.” Check these artifacts:
runs/acme-attack/
audit.db
agent.stdout
report.json
report.html
workspace/
events.jsonl
transcript.jsonl
artifacts/
For ravage scan, stdout is scan.stdout instead of agent.stdout.
Use this quick checklist:
report.json exists.audit verify succeeds.workspace/events.jsonl contains tool and report events.report.jsonStart with these fields:
summary: high-level result for the run.findings: accepted findings and their evidence.failures: benchmark or scoring failures when applicable.trace_summary: model/tool event counts when available.trace_quality: report-only diagnostics for repeated actions, missing
evidence, or malformed traces.For a finding, check:
If a report has no findings, inspect agent.stdout or scan.stdout, then
workspace/events.jsonl, to see whether the run failed early, lacked tools, ran
out of turns, or simply found no evidence.
Memory is design-stage in the current public CLI. ravage attack accepts
--memory off for reproducibility parity, but active memory retrieval, writes,
review, and promotion are not wired into the current entry point.
.venv/bin/ravage attack examples/labs/ravage-acme-box/brief.yaml \
--model-profile local-ollama \
--model-tier mid \
--memory off
Use live tool evidence for findings and flags. Treat Memory Design
as architecture context until ravage --help shows active memory commands.
For public benchmark runs, state that memory was off.
Set the benchmark root to a clean checkout, then run no-spend selection or preflight first:
export XBEN_ROOT=/path/to/validation-benchmarks/benchmarks
PYTHONPATH=packages/ravage/src:packages/schemas/src \
.venv/bin/python -m ravage xben \
--benchmarks-root "$XBEN_ROOT" \
--output-dir runs/xben/preflight \
--ids XBEN-001-24 XBEN-002-24 \
--mode black-box \
--agent ai-web \
--model-profile hosted-openai \
--model-tier low \
--tool-runtime host \
--max-turns 8 \
--max-model-requests-per-case 8 \
--preflight
Run selected cases after checking preflight:
PYTHONPATH=packages/ravage/src:packages/schemas/src \
.venv/bin/python -m ravage xben \
--benchmarks-root "$XBEN_ROOT" \
--output-dir runs/xben/selected \
--ids XBEN-001-24 XBEN-002-24 \
--mode black-box \
--agent ai-web \
--agent-mode ctf-free-roam \
--model-profile hosted-openai \
--model-tier low \
--tool-runtime host \
--max-turns 8 \
--max-model-requests-per-case 8 \
--allow-paid-models
Use --resume or --retry-failed for follow-up runs. When rerunning a failed
benchmark investigation, select only the failed IDs so results stay readable.
ModuleNotFoundError: orchestrator: run scripts/bootstrap.sh; the
virtualenv has an old console script.ravage tools check, build
ravage-kali:latest, or pass --allow-degraded when degraded mode is
acceptable.--allow-paid-models
intentionally.127.0.0.1 or
localhost, then update the brief scope and rerun.brief: YAML file describing target URL, allowed scope, objectives, and
constraints. For normal web pentests, use web_application_assessment or
api_security_assessment instead of guessing a class like xss or jwt.
Specific vulnerability classes are best reserved for targeted retests, not
clean benchmark runs. Benchmark-supplied descriptions are still allowed.ai-web: Ravage’s model-driven web testing loop.DAST: dynamic application security testing against a running target.tool recon: bounded pre-model reconnaissance with tools such as crawlers or
content discovery.source-guided: source code suggests candidates, but live target proof is
still required.proof bundle: structured evidence used to validate noisy multi-step
findings.memory: local reviewed hints. Useful for guidance, never proof.