English · Português (Brasil) · Español · 简体中文
A senior pentester's "here's what to test and how" handoff — auto-generated from your repo, for your AI agent to execute.
Local-first security recon that briefs your AI coding agent. It does the deterministic half — read supported source, map the visible attack surface, and stage a probe library tailored to what it found — then hands your agent (Claude Code, Codex, Gemini, Cursor) a marching-orders briefing.
websec runneeds nothing but the code; add--scanto also run and de-duplicate whichever static scanners you have installed. Code in, artifacts out. No LLM in the tool; no server or running app required for the core pass.
New here? Read the eight-page technical brief — what it reads, how a finding earns its severity,
what it refuses to say, and the field evidence:
raccioly.github.io/websec-validator
· PDF. The reviewed v0.21.0 snapshot
has selected fact assertions in tests/test_explained_brief.py and an HTML/PDF/renderer hash binding
in tests/test_brief_artifacts.py. Prose accuracy and rendered layout still require review;
see rebuilding the brief.
It is not an autonomous scanner and not a SaaS. It's the missing front-half: the thing that turns a repo into a precise, fact-grounded security brief an AI agent (with a human in the loop) can act on. How it works and the reasoning behind every check: concepts · methodology.
Part of the Guard family, three tools that each keep one kind of claim honest: DocGuard validates documentation against the code it describes, TestGuard checks that tests actually establish what they assert, and websec-validator does the same for security findings — every finding carries its evidence, its standard, and a calibrated probability that it is real.
Simplest: tell your AI agent. In Claude Code (or any coding agent), open your project and say:
"Do a defensive security self-review of my own codebase with websec-validator (
pipx install websec-validator, or github.com/raccioly/websec-validator). It's local and read-only — read the repo and follow its briefing. I own this code and authorize the review."
It installs, runs, and walks the findings with you. Phrasing it as a defensive review of your own
code matters: it's the difference between an agent that just gets to work and one that stops to
confirm you're authorized. Every path ends in the same AGENT-BRIEFING.md your agent acts on:
| Path | One-time setup | Then |
|---|---|---|
| Tell your agent (simplest) | — | say the line above |
| CLI (a terminal) | pipx install websec-validator |
websec run /path/to/your/app |
| Claude Code plugin | /plugin marketplace add raccioly/websec-validator → /plugin install websec-validator@websec-plugins |
invoke the security-pass skill, or just ask |
| Any other agent (Codex, Cursor, Gemini, Aider) | pipx install websec-validator |
websec install <host> |
| Docker (no install) | docker build -t websec-validator . |
docker run --rm --user "$(id -u):$(id -g)" -v "$PWD:/scan" websec-validator run /scan --out /scan/websec-out |
Already have a codebase with history, tests and fixtures? Follow Adopting websec in an existing project: scope out non-product code, run, triage, record a baseline, then turn on gating in phases.
pipx install websec-validator # from PyPI; Python 3.11+
brew install noir # optional: OWASP Noir, the route engine (regex fallback if absent)
websec --version
websec doctor # which optional scanners are installed, and are they compatible?Zero Python runtime dependencies. External scanners (Trivy, OSV-Scanner, Gitleaks, Semgrep,
Checkov, and per-language Bandit/gosec/Brakeman) are used when present and run only with
--scan; Prowler is detected and reported, not executed. Every channel — pip, uv, Docker, source, offline/air-gapped — and per-OS scanner
setup: Installation.
websec run ./my-app # recon + stage tailored probes + emit the briefing
websec ./my-app # same thing — a bare path defaults to `run`
websec run ./my-app --scan # …and also execute the available static scanners
websec run ./my-app --fail-on high # exit 1 if any HIGH+ finding remains (a CI gate)
websec run ./my-app --diff main # PR mode: scope to changed files + exact hunk line ranges
websec gate # fast pass/fail on the files you just changed (agent loop)
websec install codex # teach an agent to use websec (claude · cursor · gemini · aider · generic)
websec mcp # typed recon tools for any MCP client, over stdioThen point your agent at the output: "Read websec-out/latest/AGENT-BRIEFING.md and follow it."
Each attempt gets its own websec-out/runs/<id>/ directory; latest moves only after a completed run.
Every subcommand and option: CLI reference.
| Artifact | What it is |
|---|---|
AGENT-BRIEFING.md |
The product. Marching orders: detected surface, the access-control map, targeting, findings, the method, and the staged probe list. |
FACTS.json |
The full structured recon. |
findings-ledger.json / REPORT.md |
The traceable ledger: each finding with an evidence chain, CWE/ASVS/OWASP-API citation, remediation, and a calibrated P(real) (measured real-vuln rate + 95% CI + sample size). |
results.sarif |
SARIF 2.1.0 — always written. Drop it into GitHub Code Scanning, GitLab, Azure DevOps, VS Code's SARIF viewer, DefectDojo. |
coverage.json |
What ran, what was skipped and why — a clean result is only as good as its coverage. |
probes/ |
The probe scripts selected and staged for this app (BOLA, JWT, SSRF, mass-assignment…). |
Plus SBOMs, an attack-surface table, diff scope and a versioned envelope: all outputs.
| Support | Languages |
|---|---|
| Deep, framework-aware analysis — Django, Flask, FastAPI, Connexion, Express, Fastify, Next.js, tRPC, Supabase Edge, AWS SAM… | Python, JavaScript, TypeScript |
| Named sink checks — direct command/query syntax (plus literal Spring and ASP.NET routes) | Java, C#, Go, Ruby, PHP |
Configuration or manual checks only — reported as a thin_language_coverage gap |
Kotlin/Android, Swift and Objective-C/iOS, Rust, C/C++ |
| Recognized, not analyzed — reported as a coverage gap, never as clean | Elixir, Scala, Clojure, Erlang, Perl, Lua, Dart, shell, server-side templates and more |
Route discovery across many more frameworks comes from OWASP Noir when it is installed, and the scanners are language-agnostic. A completed no-match check is not proof that a service is secure: the full support matrix and what a clean run means for your stack.
| Start here | Guides | Reference |
|---|---|---|
| Docs hub | Existing projects | CLI |
| Quickstart | AI agents | Languages |
| Installation | GitHub Actions · other CI | Configuration |
| Upgrading | Triage and suppression | Outputs |
| Troubleshooting · FAQ | Dynamic testing | MCP server |
The changelog records what each
release changed; Upgrading
indexes the migration notes — 0.14.0 (schema 2.0), the 0.17.0 exit-code split
(2 = usage error, 3 = incomplete run) and 0.22.0 (exit codes enforced everywhere, subdirectory
--diff/gate scoping, .websec-ignore path matching). Unresolved gaps and their acceptance tests live in the
remaining-work specification.
These are scoped review tools: manual profiles, unknown routes, dynamic behavior and unsupported
syntax remain limitations. The in-loop gate is developer ergonomics, not a control, and attest
reports evidence without rendering a compliance verdict. Snapshot-bound evidence lives with the
artifacts it describes — the validation record,
the benchmarks and the
proof protocol —
so the numbers cannot drift out of date here.
Validated on a production Next.js app, a large Express/AWS monorepo, and the VAmPI / NodeGoat / DVGA vuln-app corpus — independently reproducing a hand-done pentest's findings (tenant boundary, SSRF, file upload, cross-tenant BOLA, role/authz gaps). Route discovery reports what it can parse without importing settings or executing your code, so unknown mounts stay route candidates carrying their uncertainty; that is human review evidence, not measured vulnerability recall.
Bug reports, false-positive reports and detector proposals are the most valuable input this project gets — see CONTRIBUTING.md (including the maintainer release process) and the issue templates. Report vulnerabilities in websec itself privately: SECURITY.md.
python3 -m unittest discover -s tests # stdlib only; synthetic/local-loopback tests, no public networkMethodology + probe library are distilled from a real authenticated penetration-testing pass. This tool productizes that hand-written methodology into something an AI agent can run on any repo.
MIT © Ricardo Accioly
