redveil-ui
Self-hosted dashboard for redveil scans. Burp-style workspace, real findings, zero cloud dependency.
pipx install redveil-ui
redveil-ui init
redveil-ui start
# open http://127.0.0.1:8000
⚠️ Before you start — this runs on YOUR network
redveil-ui is 100% local. No data leaves the host it runs on. The app is bound to
127.0.0.1by default — it is not reachable from other devices on your network unless you change the config. If you do expose it, every scan it launches is sent from your IP address against the target you specify. If the target isn't yours, or you don't have explicit written permission to test it, the legal and ethical responsibility is yours — not the maintainers'.Because the dashboard is self-hosted, the security perimeter is also yours: who can reach the instance, what targets you queue, and whether destructive checks are enabled. Treat it like any other local service with a security boundary.
The Probe Builder's "Custom payload" mode has a two-gate confirmation (Gate 1 + Gate 2, both required). That's not UI friction for its own sake — it's because custom payloads sit outside the curated set of redveil's built-in checks, so the framework can't pre-validate them for safety. The two gates exist so you have to pause and confirm what you're about to send.
See
DWYOR.mdfor the full statement.
what you get
The package bundles a FastAPI backend, a Next.js 16 SPA, and the
redveil library under one uvicorn
process on one port. One install, one config file, one URL to remember.
The screenshots below are taken against this exact package, served by
redveil-ui start, with a seeded scan + finding to make the data
realistic. Click any of them to view full-size.
1. Targets — register a host before you scan it
The starting point. Every scan targets a row in this list. Each row
carries the URL, an optional human label, and the YAML scope block
that the orchestrator hands to the redveil library's
ScopeController. Add a target once, scan it many times against
different profiles.
The New target button (top right) takes you to the combined
target + scan form — see "New Scan" below.
2. New Scan — target + scan config in one form
This is the primary action of the dashboard: register a target and configure the scan in a single form. Fields:
- URL (required) — validated client-side for http(s) scheme, blocked from cloud-metadata endpoints (
169.254.169.254andmetadata.google.internal). - Name (optional) — operator-friendly label.
- Scope YAML (optional) — if omitted, the auto-allow scope from
scope_check.pylets the target's host through; otherwise a strictallowed_hosts/allowed_pathsblock is enforced at scan creation. - Profile —
passive(default, read-only recon),low_impact(non-destructive probes),active(exploitation-grade; needsallow_destructive). - Destructive level ceiling —
L1throughL6. The framework refuses any scan wherelevel >= L3andallow_destructiveisfalse. - Allow destructive — opt-in unlock. Default
false. Without it, even L3+ checks are denied per-action at runtime. - Gate mode —
non_interactive(default, auto-approve and log),strict(auto-deny MEDIUM+),interactive(v2, currently disabled). - Max requests (optional) — hard cap. The form warns if you pick
activewith a budget below1500(Time-Based SQLi worst case640+ Command Injection worst case1190).
Submitting creates the target row and starts the scan in one POST pair; the page redirects to the new scan's detail page where progress streams in live.
3. Scan Detail — live progress, findings, controls
The high-traffic page during a scan. Three things stream in:
- Status pill (top):
pending→running→completed/failed. - Findings list (mid): populates as the orchestrator emits them. Each row has severity, confidence, title, endpoint, and a
Viewlink. - Event log (right rail): per-action decisions from the
ActionGate(auto-approve, denied, etc).
SSE connection: GET /api/scans/{id}/stream emits one event per orchestrator action with : keep-alive heartbeats every 15s. The Python backend uses a per-scan pub-sub (redveil_ui/api/event_bus.py) so the orchestrator can run independently of any open SSE clients — closing the tab does not cancel the scan.
4. Scan History — past runs at a glance
List of every scan the operator has run, ordered newest first. Filters: status (all / running / completed / failed) and free-text search across target URL + name. Click any row to go to that scan's detail page.
Stat tiles at the top show total scans, running count, and 7-day finding count. Empty state prompts the operator to start a new scan.
5. Dashboard — entry point
Recent activity, stat tiles (total scans / active targets / 7-day findings), and quick links to create targets or review history. Sidebar nav gives one-click access to every section.
6. Target / Site Map — per-target endpoint inventory
Drill-down view for a single target: every endpoint the orchestrator
discovered during scans, grouped by folder, with per-endpoint finding
counts and severity histograms. Pulls from
GET /api/targets/{id}/sitemap.
7. Evidence Log — every request/response captured
All Evidence objects written by the orchestrator during scans. Each row has the timestamp, endpoint, HTTP method, status code, body length, and a short body excerpt. Filterable by method, check_id, and status_min/status_max. Click a row to expand the full request/response.
This is the same evidence that powers the ReplayEngine and the
confidence = oracle × (1 + log2(distinct_dims)) × weight − env_penalty − uncertainty scoring in the underlying redveil library.
8. Finding Detail — investigate one finding
For a single finding: severity, confidence, CWE / OWASP tags,
technical_explanation (why the orchestrator marked this as a finding),
and remediation (what to do about it). The Replay button runs the
captured ReplayRecipe N times to verify reproducibility — see Replay
below.
9. Replay — verify reproducibility
Takes the captured ReplayRecipe (request method + URL + body + headers) and re-issues it N times. If the timing-signal reproduces consistently, the finding's confidence is corroborated; if it flakes, the
finding is demoted. The redveil library's ReplayEngine runs the
samples; this UI just configures sample count and shows the verdict.
If the original finding has no replay_recipe (some checks don't
capture one — that's documented in the model), the Replay button is
hidden and a "Replay not available" callout shows why.
10. Probe Builder — manual targeted probing
Operator-initiated probes, separate from the automatic checks. Two modes:
- Preset — pick a built-in check (e.g.
sqli-time-based) and the client fetches its payload set fromGET /api/probes/payload-sets. Select by index, no string input. - Custom — write your own payload string. The form requires
confirmed_dwyor: truein the POST body and the endpoint enforces this withHTTP 403if missing — the two-gate DWYOR confirmation (Gate 1expand to acknowledge, thenGate 2type-to-confirm). This is the "outside curated checks" path mentioned in the warning at the top of this README.
The Probe Builder reuses the same HttpClient + ScopeController as
the automatic checks, so the same scope/destructive-level rules apply.
A custom probe that violates scope is rejected by HttpClient with
ScopeViolation before any request is sent.
11. Plugins — 19 checks at a glance
Read-only list of every check plugin discovered from the installed
redveil library via its entry_points = redveil.checks metadata. The
list comes from GET /api/checks. This is the same source the
orchestrator loads at scan start, so a 19-check install of redveil
shows 19 cards here, dynamically — no static copy.
12. Decoder + 13. Comparer + 14. Token Entropy — utility trio
| Decoder | Comparer | Token Entropy |
| Multi-format decode (base64, hex, URL, HTML entities, JWT split). | Side-by-side evidence diff for two captured requests. Calls redveil.knowledge.Comparer to diff structured fields. |
Shannon entropy + per-token analysis. POST /api/entropy/analyze. |
15. Settings — the live config, not a hardcoded page
Reads the same ~/.redveil-ui/config.yaml that redveil-ui init wrote
and the server reads at startup. Every field shown here is the value
the running process is actually using (host, port, data_dir,
reports_dir, gate_mode, max_destructive_level, allow_destructive).
No fake / hardcoded values.
why redveil-ui vs the CLI
redveil-ui (this package) |
redveil CLI |
Burp / Nessus / enterprise platforms | |
|---|---|---|---|
| Interface | Browser dashboard, one port, real-time SSE | Terminal, exit code, JSON output | Heavy Java/Electron client, often paid |
| Hosting | 100% local, 127.0.0.1 by default |
Your shell | Cloud / licensed server |
| State | SQLite at ~/.redveil-ui/data/ |
Per-run directory under reports/ |
Project server, often remote |
| Probe library | Same 19 checks via the installed redveil library |
Same 19 checks | Different ecosystems |
| Replay | One click in the UI | redveil replay <report-dir> |
Manual via Intruder/Comparer |
| Cost | Free, MIT, self-hosted | Free, MIT, self-hosted | $400+/yr per seat |
| Best for | Solo operators running scans on their own schedule | CI / scripted / scripted | Teams with budget + need for shared state |
If you only run scans from cron or CI, the CLI is enough. If you want to sit at a browser while a scan runs, see findings populate, dig into evidence, and replay individual results, this is the interface.
architecture
Browser (port 8000)
│
│ HTTP / SSE
▼
Uvicorn :8000 (single process)
│
├─► FastAPI app (redveil_ui.api.main)
│ ├─► /api/* routers
│ │ ├─ /api/targets, /api/scans, /api/findings
│ │ ├─ /api/checks, /api/probes/*
│ │ ├─ /api/entropy/analyze
│ │ └─ /api/scans/{id}/stream (SSE)
│ ├─► redveil_ui.api.event_bus (per-scan pub-sub for SSE)
│ └─► Static SPA fallback: serves ui/frontend/out/{route}.html
│ └─► React Router hydrates the rest
│
└─► redveil_ui.scanner (orchestrator)
│
│ imports from `redveil` (installed lib, version pinned ≥1.9.6)
▼
redveil.orchestrator.run(scan)
→ redveil.http.HttpClient (with ScopeController)
→ redveil.plugins.check_registry
→ redveil.validation.ActionGate
→ redveil.reporting.markdown.write_report
→ redveil_ui.api.event_bus.publish (for SSE)
One port, one process, one SQLite file. The frontend is a static export served by the same uvicorn. There is no separate API server, no reverse proxy, no Redis, no Postgres.
requirements
- Python ≥ 3.11
- redveil ≥ 1.9.6 (auto-installed as a dependency)
- ~80 MB disk for the wheel + transitive deps in a fresh venv
- A free TCP port (default
8000; the init command picks the next free port if8000is taken)
redveil must be importable as import redveil — the dashboard will
fail-fast at startup if it isn't.
status & roadmap
0.1.0 is feature-complete for the documented surface. All 15 routes render, all major actions work, 1101/1101 library tests pass, 19/19 dashboard e2e tests pass on a fresh install in a clean venv.
known limitations (roadmap, not blockers)
false_positiveUI toggle — the API endpoint filters false positives by default with?include_fp=trueopt-in, but the dashboard's Findings list doesn't expose the toggle yet. Filed for 0.2.0.- SQLite WAL mode + startup recovery sweep — single-writer SQLite can lock under heavy write loads. No retry-on-lock in the current scanner. A WAL mode +
busy_timeout=5000event-listener + startup-recovery sweep for orphan'running'scans is filed for 0.2.0. max_requestsUI in scan list — server-side cap (Field(gt=0, le=100000)) is enforced; per-scan row display in/scansdoesn't surface it. Cosmetic.- Empty-state contract — list endpoints return
[]for empty DB;/api/scans/{id}/evidencereturns404(not[]) for an unknown scan id. UI handles both. Maybe align to[]in 0.2.0. - e2e_lab + negative_testing tests are backend integration tests shipped with the
redveillibrary. They run cleanly (8 + 4 = 12 pass) and are listed in the library's CI, not the dashboard's acceptance criteria.
security posture (relevant for review)
The redveil-ui API applies the same safety checks as the redveil CLI:
- URL safety (always-blocked at the schema layer):
file://,ftp://,javascript:,data:,169.254.0.0/16(incl. AWS IMDS),168.63.129.16(Azure WireServer),metadata.google.internal(GCP). RFC1918 + loopback are allowed but must be in the target'sallowed_hostsscope. - Scope check runs synchronously at scan creation. Out-of-scope scan →
403, scan never starts. - Destructive level:
L3+requiresallow_destructive: true. Refusal is422with a clear message. - Probe Builder requires
confirmed_dwyor: truein the body, validated server-side. - YAML parse failure in
scope_yamlis a hard error (rejected with422), not a silent fallback to "allow everything". - Loopback default: server binds
127.0.0.1only. LAN exposure requires a config edit.
see also
- redveil — the underlying scanning library.
redveil-uiis a thin operational layer over it. - FitzyPrjkt/Redveil — full source tree (library + UI + docs in one monorepo).
USER_GUIDE.md— detailed walkthrough of CLI install + scan invocation.CONTRIBUTING.md— how to add a new check plugin.SECURITY.md— full safety model and how to report issues.
license
MIT. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file redveil_ui-0.1.3.tar.gz.
File metadata
- Download URL: redveil_ui-0.1.3.tar.gz
- Upload date:
- Size: 1.5 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6e121b1b501441660073756b38ca3dbb54c993f2811765a594fdbab05b25dbe0
|
|
| MD5 |
f60fef573d5e1d2351ea66ddce19b8a5
|
|
| BLAKE2b-256 |
c84bb65d00ee284599de6c18ed23e1b7af3df7c68ec02c700be483ee647ccdeb
|
File details
Details for the file redveil_ui-0.1.3-py3-none-any.whl.
File metadata
- Download URL: redveil_ui-0.1.3-py3-none-any.whl
- Upload date:
- Size: 777.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
368deadda018c3079e9ddfb6534bc82731e0d01cc16fa0812111e7ff9964a0e3
|
|
| MD5 |
ae8dbde39647aebf3ec25bf14dacd823
|
|
| BLAKE2b-256 |
cde38ad19f0b4fc65575b9f22564e1bb39ab12417247e3594bbc3a380d1a2213
|