websec-validator
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.
Getting Started — just point it at your repo
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.
Install
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.
Usage
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 stdio
Then 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.
What you get (websec-out/)
| 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.
Languages
| 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.
Documentation
| 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 |
Status
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.
Contributing
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 network
Credits
Methodology + 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.
License
MIT © Ricardo Accioly
Metadata
Release files for websec-validator 0.22.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| websec_validator-0.22.0.tar.gz | 924.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| websec_validator-0.22.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.6 MB
Release files / websec_validator-0.22.0.tar.gz
| Download URL | websec_validator-0.22.0.tar.gz |
|---|---|
| Size | 924.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
572e73c6d2d63c34f4d5af75464a0993aa9c8e9e3807c18b2bd95231cd78dddf
|
|
BLAKE2b-256 checksum How to use checksums |
ae2f66074a473b6b1c9367a50dd1959de30af260feb73a0b35e72c2e4484fe98
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logRelease files / websec_validator-0.22.0-py3-none-any.whl
| Download URL | websec_validator-0.22.0-py3-none-any.whl |
|---|---|
| Size | 650.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cc8cd0f76f8f0d7bf040a6fa42e4ddf3566df19ce142bf4be96b50023e2a427f
|
|
BLAKE2b-256 checksum How to use checksums |
fe062e283d8653ce1f81107f61ebfb54f35b015468c3fab1ad4bb65900b9cfa2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency log