内容
# websec-validator
[](https://github.com/raccioly/websec-validator/actions/workflows/ci.yml)
[](https://pypi.org/project/websec-validator/)
[](https://pypi.org/project/websec-validator/)
[-brightgreen)](#install)
[](#ci--enterprise-integration)
[](LICENSE)
<!-- docguard:quality negation-load off — "no LLM / no server / no running app / not a SaaS / never touches prod" is this tool's core positioning; defining it by contrast with the scanners-and-SaaS it deliberately is NOT is intentional, not a phrasing defect. -->
> 本地优先的安全性评估工具,为您的 AI 编码代理提供简报。它完成确定性的一半 - 读取仓库,映射整个攻击面,运行并去重静态扫描器,并为其发现的内容量身定制探针库 - 然后将带有行进命令的简报交给您的代理(Claude Code、Codex、Gemini、Cursor)。**代码输入,工件输出。工具中没有 LLM,没有服务器,没有运行的应用程序。**
它 **不是** 一个自主扫描器,**不是** 一个 SaaS。它是缺失的前半部分:将仓库转化为精确的、基于事实的安全性简报,AI 代理(有人工在环中)可以据此采取行动 - 一种自动填充的、仓库感知的版本,由资深渗透测试人员的“这里要测试什么以及如何测试”移交。
## 入门指南 - 只需指向您的仓库
**最简单:告诉您的 AI 代理。** 在 Claude Code(或任何编码代理)中,打开您的项目并说:
> *"使用 websec-validator 对 **我自己的** 代码库进行防御性安全自我审查(`pipx install websec-validator` 或 github.com/raccioly/websec-validator)。它是本地且只读的 - 读取代码库并遵循其简报。我拥有此代码并授权审查。"*
它安装,运行,并与您一起查看发现结果。无需托管,无需网站 - 它是本地的。(将其描述为 **您自己的代码的防御性审查** 很重要:这是在代理只是直接开始工作和停止确认您已授权之间的区别 - 工具默认是本地且只读的,但通用“渗透测试”可能被视为攻击某些东西的请求。)有四种方法可以实现相同的效果,最终都是相同的 `AGENT-BRIEFING.md`,您的代理会根据它采取行动:
| 路径 | 一次性设置 | 然后 |
|---|---|---|
| **告诉您的代理** (最简单) | - | 说上面的那句话 |
| **CLI** (终端) | `pipx install websec-validator` | `websec run /path/to/your/app` |
| **Claude Code 插件** (斜杠) | `/plugin marketplace add raccioly/websec-validator` → `/plugin install websec-validator@websec-plugins` | 调用 **security-pass** 技能,或直接询问 |
| **Docker** (无需安装) | `docker build -t websec-validator .` | `docker run --rm --user "$(id -u):$(id -g)" -v "$PWD:/scan" websec-validator run /scan --out /scan/websec-out` |
➡️ **想要了解每个检查背后的原因?** 阅读 **[docs/METHODOLOGY.md](docs/METHODOLOGY.md)** - 每个测试的作用及原因。
## 安装
```bash
pipx install websec-validator # 从 PyPI
brew install noir # OWASP Noir - 路由引擎(50+ 框架); 如果不存在则使用正则表达式回退
websec --version
```
_直到第一个 PyPI 版本发布(或对于最新版本),请直接从源代码安装:_
`pipx install git+https://github.com/raccioly/websec-validator` (或从克隆:`pipx install .`)。
需要 **Python 3.11+** (在 stock macOS 上,`python3` 通常是 3.9 - 使用 `pipx`,它会选择更新的解释器,或通过 Homebrew/pyenv 安装)。零 Python 运行时依赖:它调用扫描器(Trivy、Gitleaks、Semgrep/OpenGrep、Checkov、Prowler)和 Noir **当存在时**,报告缺少的内容,如果某个工具不存在则不会硬性失败。
### 或通过 Docker 运行(所有内容都已捆绑,零安装)
无需安装 Noir 或任何扫描器 - 镜像中已捆绑所有内容(架构感知,amd64 + arm64):
```bash
docker build -t websec-validator .
docker run --rm --user "$(id -u):$(id -g)" -v "$PWD:/scan" websec-validator run /scan --out /scan/websec-out
```
镜像中包含 Noir + Trivy + Gitleaks + Semgrep + Checkov;将您的仓库挂载在 `/scan`,工件位于 `/scan/websec-out`。
## 用法
```bash
websec run ./my-app # ← 一个命令:recon + 量身定制探针 + 发出简报
websec ./my-app # 相同 - 裸路径默认为 `run`
websec run ./my-app --scan # …并执行可用的静态扫描器
websec run ./my-app --format sarif # SARIF 2.1.0 输出到 stdout(用于输送到 CI); 同时始终写入到运行目录
websec run ./my-app --fail-on high # 如果存在任何 HIGH+ 发现,则退出 1(一个 CI 门控)
websec doctor ./my-app # (可选)哪些扫描器已安装?
websec mcp # 作为 MCP 服务器通过 stdio 运行(用于任何 MCP 客户端的输入重建工具)
```
然后将您的代理指向输出:**"读取 `websec-out/AGENT-BRIEFING.md` 并遵循它。"**
> 这是整个用户界面: **`run`** (加上可选的、先进的 **`dynamic`** 实时探测步骤)。`recon`/`proof`/`calibrate` 存在用于开发工具本身,隐藏在 `--help` 中 - 您永远不需要它们。
## 它提取的内容(20 个确定性提取器,无 LLM)
| | 维度 | 值得注意的输出 |
|---|---|---|
| stack | 语言、框架、数据存储 | 意识到 monorepo(聚合每个清单) |
| routes | 通过 **OWASP Noir** 的每个端点(+ Supabase-edge,**AWS SAM / Function-URL**) | 方法 · 路径 · 类型参数 · 代码路径 · **AuthType:NONE 公共端点** |
| auth | 方案 + 登录界面 + **不安全的默认签名密钥** + **破碎的身份验证后门** | 多方案;标志硬编码 `JWT_SECRET \|\| 'dev-secret'` 后备(可伪造的 JWT),**dev- 令牌 / 接受任意密码的后门** (完全绕过,严重),以及 **fail-open** `if(env.SECRET)` 签名检查 |
| **authz** | 访问控制映射 | 保护范围(包括 **路由器安装身份验证**)+ **具有可见保护的写入端点** + 角色 |
| **authz_dataflow** | authz **正确性**(保护是否信任正确的内容?) | **未签名 cookie 授权** · **声明键控身份验证** (用户影响的 JWT 声明)· **事务本地 RLS 上下文** (重置前查询) |
| tenant | 多租户密钥候选人 | BOLA 边界,按频率 |
| **password_policy** | 跨路由一致性 **+ 重用/历史记录** | 路由间 **+ 设置密码路径无重用检查的哈希** |
| surface | 16 个接收类 **+ 重定向 SSRF** | 用户输入门控接收器(包括 **通过对象扩展的批量赋值** 和 **反射的/DOM/模板 XSS** - `innerHTML`/`dangerouslySetInnerHTML`/`v-html`/`\|safe`, sanitizer 门控)+ 变参 SSRF + 错误披露 + 遵循重定向无每跳保护 **+ 反向代理前缀转义 + 主机头开放重定向 + SSRF-redirect-hardening** |
| **upload_security** | 无限制上传 + 不安全服务 | 仅拒绝列表,存储的文件名来自文件名,信任客户端 MIME,接受 SVG,**服务时不使用 `nosniff`** |
| schemas | 数据模型 + **特权字段** | Pydantic/SQLAlchemy/Django/Prisma/Mongoose/TypeORM/Zod → `role`/`isAdmin`/`groupId` 用于批量赋值目标 |
| iac_ci | IaC + CI/CD | GHA 注入(**run:-position-aware**),未固定的操作,tfstate,CDK AppSync `API_KEY` 匿名默认身份验证,**docker-compose host-takeover (docker.sock / pid:host / privileged)+ `.gitleaksignore` 秘密抑制审计** |
| client_exposure | 浏览器泄漏 | **按名称 + 值形状公开变量的秘密** (`da2-…`)+ CDK 构建注入,客户端秘密,源映射 |
| **client_integrity** | 可篡改显示(客户端信任边界)+ **WS 身份验证模型** | 任何安全关键的接收值(地址/IBAN/2FA-种子/API-key/webhook)用户读取或复制,无严格 CSP / 带外锚点 **+ 客户端篡改向量,磨砂指纹,过度声明控制,CSWSH 判定器** |
| **transport_security** | CSP + HSTS + **CORS** + **SRI** + **clickjacking** + **CSRF** 基线 | 缺失/弱 CSP,内联事件处理程序,部分 HSTS,**CORS reflect-origin+credentials,外部脚本无 SRI,monorepo `next.config` 头部间隙,框架无关的 clickjacking(无 X-Frame-Options / `frame-ancestors`),CSRF(cookie-auth + 无令牌库 + 无 SameSite)** |
| **pii_exposure** | 输出边界处未屏蔽的 PII | `res.json(rawEntity)` 包含 PII + **定义的屏蔽控制但无实时调用站点** (值形状,非字段名称) |
| graphql | GraphQL 界面 | **AppSync `introspectionConfig: DISABLED`-aware**)/ playground / 深度限制 **+ AppSync 订阅身份验证(跨组 BOLA)** |
| integrations | 第三方 + Webhooks **+ 输出动作端点** | 无签名 Webhooks **+ 具有无身份验证或仅 IP 速率限制的电子邮件/SMS/push 处理器 + 冗余的秘密获取** |
| **llm_security** | LLM / AI 代理界面(**OWASP LLM Top 10**) | 间接 **提示注入** (不受信任的 RAG/工具内容 → 提示)· **不安全的输出处理** (模型文本 → 工具调度)· **过度的代理** · **无边界生成** (无 maxTokens/超时)· **防护失败开放** |
| **crypto_usage** | 加密 API 正确性 | **弱密码哈希** (快速/无盐 SHA-256/MD5)· `jwtVerify` 无算法允许列表 · **可预测主体** (id = 哈希邮件) · 非恒定时间秘密比较 |
加上 **派生目标** - IDOR / SSRF / 开放重定向 / 上传 / 写入 / 身份验证端点候选人 - 以便探针指向 **确切** 的端点,而不是盲目触发。
## 您获得的内容(`websec-out/`)
| 工件 | 它是什么 |
|---|---|
| `AGENT-BRIEFING.md` | **产品。** 行进命令:检测到的表面,访问控制映射,目标,查找,方法,和分阶段的探针列表。 |
| `FACTS.json` | 完整的结构化recon。 |
| `findings.json` | 静态扫描器结果,**跨工具去重** 和严重性排名(使用 `--scan`)。 |
| `findings-ledger.json` / `REPORT.md` | 可追溯的账本:每个查找带有证据链,CWE/ASVS/OWASP-API 引用,补丁建议,和 **校准的 `P(real)`** (测量的真实漏洞率 + 95% CI + 样本大小)。 |
| `results.sarif` | **SARIF 2.1.0** - 始终写入。将其放入 **GitHub 代码扫描** (内联 PR-diff 注释 + 安全选项卡),GitLab,Azure DevOps,VS Code 的 SARIF 检视器,DefectDojo。 |
| `findings.envelope.json` | **版本化,自描述** 的 JSON 信封(`schema_version`)周围的账本 - 非 GitHub CI / 仪表板不应反向工程内部形状。 |
| `probes/` | 为 **此** 应用程序选择的探针脚本(BOLA,JWT,SSRF,批量赋值...)。 |
## 流程
```
🔧 websec (确定性) 🤖 您的代理 + 🧑 您
───────────────────────────────── ─────────────────────────────────
1. recon → 完整的攻击面 → 确认租户边界 + 身份验证模型
2. 运行 + 去重静态扫描器 → 区分真实和噪音
3. 分阶段定制探针 → 填充占位符,运行 vs TEST 实例
4. 发出 AGENT-BRIEFING.md → 提出修复建议,重新运行以确认,报告返回
```
静态recon + 简报仅需要 **代码**。**运行** 探针需要一个实时测试实例 + 测试凭证(人类提供它们)- 工具本身从不触及运行的应用。
## CI / 企业集成
recon 与否 - 这些只是使其输出可被管道、仪表板和非 Claude 代理消耗的工具。所有标准库,无需新依赖。
**SARIF → GitHub 代码扫描。** 每次运行都会写入 `results.sarif`(SARIF 2.1.0)。上传它,每个查找结果会 **内联显示在 PR 差异** 和 **安全选项卡** 中,按安全严重性频段排名,并附有 CWE/ASVS/OWASP 引用和补丁建议。
**阻止构建。** `--fail-on {critical,high,medium,low}` 在达到或超过该严重性级别时退出非零 - 一个真正的 CI 门控,默认为仅报告。
**仅对新引入的内容失败。** `--baseline <prior findings-ledger.json>` 标记每个查找 `new` / `unchanged` / `fixed` (稳定的每个查找的指纹显示为 SARIF `baselineState`),而 `--fail-on` 然后仅计算 **新引入的** - 因此旧的遗留问题不会阻止每个 PR,但新引入的 SSRF 不会。
**GitHub Action** (`action.yml`):
```yaml
# .github/workflows/security.yml
name: security
on: [pull_request]
permissions:
contents: read
security-events: write # required to upload SARIF to Code Scanning
jobs:
websec:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: raccioly/websec-validator@v1
with:
path: .
fail-on: high # 阻止 PR 上新的 HIGH+(省略仅报告)
# baseline: .websec/baseline-ledger.json # optional: gate only on NEW findings
```
**MCP 服务器(任意代理,不仅仅是 Claude Code)。** `websec mcp` 通过 stdio 讲述 **Model Context Protocol**,暴露输入重建工具 - `websec_recon`,`websec_findings`,`websec_sarif`,`websec_briefing` - 因此 Cursor / Cline / Windsurf / Zed 可以直接调用recon,而不是 shelling out 并解析 stdout。在您的 MCP 客户端中注册:
```json
{ "mcpServers": { "websec": { "command": "websec", "args": ["mcp"] } } }
```
**版本化契约。** `FACTS.json`,`findings-ledger.json` 和 `findings.envelope.json` 都带有版本号;JSON 模式随软件包一起提供(`schemas/facts.schema.json`,`schemas/ledger.schema.json`),下游工具可以根据稳定形状进行验证。
## 证明框架
`websec proof` 克隆了一个漏洞应用程序库(VAmPI,NodeGoat,DVGA),并评估recon是否浮现每个应用程序的记录攻击面 - 一个确定性,可跟踪的CI代理(目前 **10/10**)。实际的杀伤力标准(是否recon提高了代理的漏洞发现率而不是通用提示?)是手动 A/B 测试 [`corpus/PROOF-PROTOCOL.md`](corpus/PROOF-PROTOCOL.md)。
## 校准信心
`websec calibrate` 将账本与标记的语料库运行,衡量每个(攻击类别,置信度)桶有多少次实际记录的漏洞,并写入 `calibration.json`(随软件包一起提供并在运行时应用)。每个查找结果都带有具有 **95%Wilson置信区间** 和样本大小 `n` 的 `P(real)` - 因此“MEDIUM”不再是一种感觉,而是“实际〜57%的时间在语料库上(CI 43-70%,n = 51)”。一个发现结果如果与任何记录的漏洞不匹配,则被视为假阳性(语料库有详细的记录)。 **诚实的警告:** 语料库 **故意** 容易受到漏洞攻击,因此对于干净的生产代码,速率会 **乐观** 倾斜,而小样本意味着 **宽区间** - CI 是标题,而不是点估计,并且随着语料库的增长,它们会收紧。数据不足时,桶会回落到每个标签的聚合值,然后是一个明确标记的未校准先验。没有 ML,没有依赖项 - 二项式比例 + Wilson 间隔;结构升级到等渗回归,如果存在一个大型标记集。
**它自我改进。** `websec dynamic` 是一个 **预言家**:写入一个未经身份验证的操作是确认的真实漏洞,而一个recon标记的端点结果证明是身份验证强制的,是一个确认的假阳性。每次动态运行都会将那些确认的标签折叠到一个 **本地覆盖** (`~/.cache/websec-validator/`,gitignored,永远不会发送) - 所以数字 **个性化您的应用程序**,您运行的次数越多,带有额外的步骤,没有任何东西离开您的机器。要手动标记,请将 `{attack_class, confidence, is_real}` 文件提供给 `websec calibrate --ingest`.
## 动态阶段(v2 - 目前仅限只读)
当您有一个 **正在运行的测试实例** 时,`websec dynamic` 铸造角色令牌并运行recon指向的探针。 v1 是 **只读**:对跨租户 BOLA 进行身份验证的 **GET 读取** 端点recon发现。
```bash
cp dynamic-config.example.json dynamic-config.json # TEST target + role creds (gitignored)
websec run ./my-app # static recon → websec-out/FACTS.json
websec dynamic --config dynamic-config.json --facts websec-out/FACTS.json
# → "14/14 跨租户GET读取被阻止 - 所有隔离" (或 🚨 LEAK 带有确切的端点)
```
永远不要指向生产环境。写入动词 BOLA,JWT/身份验证攻击和 ZAP/Nuclei 两角色差异是下一个动态探针(显式门控 - 它们会改变)。
## 验证
在一款生产Next.js应用中,一款大型Express/AWS monorepo,以及VAmPI / NodeGoat / DVGA漏洞应用库中 - 独立重现手动渗透测试的发现结果(租户边界,SSRF,文件上传,跨租户BOLA,角色/身份验证漏洞)。
## 测试
```bash
python3 -m unittest discover -s tests # 仅限标准库,无Noir/网络 - 285个测试
```
## 版本发布(维护者)
通过 **Trusted Publishing** (OIDC - 存储库中无API令牌)发布到PyPI。要创建版本:
```bash
# 1. 将版本号在pyproject.toml中增加(例如 0.2.1 → 0.2.2)
# 2. 用版本号标记并推送 - 该标签必须与pyproject的版本号匹配(CI验证):
git tag v0.2.2 && git push origin v0.2.2
# → publish.yml 构建,安装 + 烟雾测试轮子(版本匹配,
# 校准发货,实际的`websec run`),然后发布。构建失败。
```
# 不需要达到 PyPI — 这样您就无需在事后进行修改。
## 一次性 PyPI 设置(在首次发布之前):在 pypi.org 上 → **账户 → 发布 → 添加待定发布者**,项目为 `websec-validator`,所有者为 `raccioly`,仓库为 `websec-validator`,工作流为 `publish.yml`,环境为 `pypi`。该项目在首次成功发布时创建。
> 两个独立的渠道,两种更新机制:**CLI** 发布到 **PyPI**(语义版本发布,`pip install --upgrade`);**Claude Code 插件** 从 **git** 发布(跟踪最新提交,通过 `/plugin marketplace update` 刷新)。
## 状态 / 路线图
**已完成:** 20-提取器重新检测(包括 **WebExtension 客户端信任提取器** — 客户端授权门控 / 过宽的主机权限 / `world:"MAIN"` / 未验证的外部消息 — **许可/授权验证信任** 传递 — 撤销绕过 + 无每个许可使用限制,供应商无关 — **Deno/Supabase-edge + Chrome-extension** 堆栈和路由建模,**授权正确性数据流提取器** — 未签名 cookie / 声明密钥授权 / 事务本地 RLS — 以及 **CORS 错误配置**、**SRI**、**主机头开放重定向** 和 **SSRF 重定向强化** 类别,模式/实体 → 大规模赋值目标,**AWS-CDK / 受管 AppSync / VTL 边界**,**上传安全** + **PII 输出边界** + **重定向 SSRF** + **密码重复使用** 类别,一个 **浏览器中间人 / 可篡改显示** 类别,一个 **LLM / AI 代理提取器**(OWASP LLM 顶部 10 — 提示注入 / 不安全输出 / 过度代理 / 无边界生成 / 保护栏失败打开),一个 **加密使用提取器**(弱密码哈希 / jwtVerify-without-算法 / 可预测主体),**docker-compose 主机接管** + **`.gitleaksignore` 机密抑制** 审计,和一个 **反向代理前缀逃逸** 检测器),跨工具去重 + **捆绑 Semgrep 规则**,**路由器安装身份验证建模**(减少 Express 单体仓库缺少身份验证的误报),定制探针分段,代理简报,可追溯的发现账本与 **校准置信度(CJE — Wilson CIs)**,证明套件,测试套件(285),**Docker 捆绑**(所有扫描器 + Noir,架构感知),**动态阶段 v1**(经过身份验证的只读跨租户 BOLA — 验证实时,重现手动渗透测试的 14/14)。针对 **REF-PENTEST 渗透测试 + 重测** 验证,并在大型现实世界 LLM 代理单体仓库中重新验证(高发现噪声 178 → 15,AI + 加密表面新覆盖)。
**接下来:** 动态写谓词 BOLA + JWT/身份验证探针 + ZAP/Nuclei 两角色差异(门控,它们会变异),在手动标记的现实仓库上校准(更具代表性的基准率),ASVS 索引查找,可选模型 SDK 适配器,用于无代理回退。
## 将其用作 Claude Code 技能 / 插件
此仓库 **是** Claude Code 插件。安装它一次 —
```bash
/plugin marketplace add raccioly/websec-validator
/plugin install websec-validator@websec-plugins
```
— 并且捆绑的 **安全通行** 技能([`skills/security-pass/SKILL.md`](skills/security-pass/SKILL.md))允许您直接用英语询问安全通行:它运行 `websec`,读取简报,并与您一起处理发现的问题。对于其他代理,通用接口保持不变:运行 CLI,读取 `AGENT-BRIEFING.md`。
**安装注意事项(现场测试):**
- 安装 ID 为 `plugin@marketplace` — `websec-validator@websec-plugins`(来自 `.claude-plugin/marketplace.json` 的市场名称),**不是** `@websec-validator`(仓库)。
- 插件仅提供 **指令**;实际扫描是一个 **单独的 Python CLI** (`websec`)。技能的步骤 0 在缺少时安装它(`pipx install websec-validator`)。
- **`/plugin …` 仅在终端 CLI 中有效。** 在 Claude **应用 / 代理 SDK**(无 `/plugin`)中,在 `.claude/settings.json` 中配置它:
```json
{
"extraKnownMarketplaces": {
"websec-plugins": { "source": { "source": "github", "repo": "raccioly/websec-validator" } }
},
"enabledPlugins": { "websec-validator@websec-plugins": true }
}
```
这 **注册 + 启用** 插件,但 **不** 自动获取它 — 首次下载仍然需要 CLI (`/plugin install websec-validator@websec-plugins`) 一次。(项目 `.claude/settings.json` 用于团队;`~/.claude/settings.json` 用于您)。
## 致谢
方法和探针库提炼自实际的身份验证渗透测试过程。该工具将手动编写的方法产品化,使 AI 代理能够在任何仓库上运行。
## 许可证
[MIT](LICENSE) © Ricardo Accioly
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器