yagyeshVyas/VibeGuard
GitHub: yagyeshVyas/VibeGuard
一款完全离线的本地安全扫描工具,专为检测和修复 AI 生成应用中的密钥泄露、注入漏洞等安全问题而设计。
Stars: 2 | Forks: 0
```
$ npx @yagyeshvyas/vibeguard scan
VibeGuard security scan
./my-app
CRITICAL api/route.ts:3 [secret.openai-key]
OpenAI API key hardcoded in server code
fix: Move to environment variable.
HIGH db/query.ts:5 [taint.sql-injection]
User input flows into SQL query via template literal (dataflow-confirmed)
fix: Use parameterized queries / prepared statements.
HIGH app/page.jsx:8 [taint.xss-dom]
User input from URLSearchParams reaches innerHTML — DOM XSS
fix: Use textContent instead of innerHTML. Sanitize with DOMPurify if needed.
Grade D (12 files) 1 critical 3 high 2 medium 1 low
Run vibeguard fix to auto-fix 4 issues
```
## 快速开始
```
npx @yagyeshvyas/vibeguard scan
```
或者使用单条命令实现全面防护(daemon + hooks + shell guard):
```
npx @yagyeshvyas/vibeguard auto # full protection on
npx @yagyeshvyas/vibeguard auto --stop # turn it off
```
### 接入 Claude Code
```
claude mcp add vibeguard -- npx @yagyeshvyas/vibeguard mcp
```
### 接入 Cursor / Windsurf
添加到你的 MCP 配置中:
```
{ "mcpServers": { "vibeguard": { "command": "npx", "args": ["@yagyeshvyas/vibeguard", "mcp"] } } }
```
## 它能捕获什么
**客户端代码中泄露的 Stripe 密钥**
```
const key = "sk_live_51H8x..."; // anyone with devtools can issue refunds
```
VibeGuard 可标记 50 多种密钥类型 —— OpenAI、AWS、GitHub、Stripe、Slack、Firebase —— 并提示你将它们移至 `process.env`。
**向全球开放的 Supabase 数据库**
```
create table posts ( ... ); -- no RLS — anyone can read/write all rows
```
检测缺失的 RLS、虚假的 RLS 策略(`USING (true)`)以及客户端组件中的 service-role 密钥。
**通过模板字面量进行的 SQL 注入**
```
db.query(`SELECT * FROM users WHERE id = ${req.body.id}`);
```
AST 污染分析可追踪从 `req.body.id` 经由模板字面量到 `query()` 的过程 —— 这是经过确认的数据流,而非正则表达式猜测。
**系统提示词中的 Prompt 注入**
```
{ role: "system", content: "You are " + req.body.prompt }
```
捕获注入到系统角色的用户输入 —— 这是大多数 Prompt 注入攻击的根本原因。
**带有请求数据的 `dangerouslySetInnerHTML`**
```
```
标记跨 React、Vue(`v-html`)、Angular(`innerHTML`)以及原生 `innerHTML` / `outerHTML` / `insertAdjacentHTML` 的 XSS 注入点。
**没有迭代上限的 AI agent 循环**
```
while (true) { await agent.step(); }
```
检测无上限的 agent 循环 —— 避免 API 无限开销和资源耗尽。
**硬编码的 JWT 密钥**
```
jwt.sign(payload, "mysecret123"); // token forgery
```
捕获配置文件、Dockerfiles 和 Kubernetes secrets 中的硬编码会话密钥、JWT 密钥和凭据。
**来自 LLM 输出的 Shell 命令**
```
const completion = await openai.chat.completions.create({...});
exec(completion.choices[0].message.content); // RCE via prompt injection
```
唯一能够检测 LLM 输出到达 `exec`、`eval`、SQL 查询和 DOM 注入点的扫描器。
## `vibeguard auto` — 单条命令实现全面防护
```
vibeguard auto # activates everything
vibeguard auto --status # see what's active
vibeguard auto --stop # reverse everything, restore backups
```
| 层级 | 功能 |
|-------|-------------|
| Daemon | 监控文件,并在每次更改时自动扫描(300ms 防抖) |
| Pre-commit hook | 遇到严重级别发现时阻止 git 提交 |
| Post-edit hook | 在 AI agent 编辑文件后自动扫描文件 |
| Shell guard | 在执行前拦截危险命令(`rm -rf`、`sudo`、`curl\|sh`) |
所有状态都存储在 `.vibeguard/auto.json` 中。幂等操作 —— 安全地运行两次。`--stop` 会逐字节恢复一切状态。
标志:`--ci`(pipeline 模式,遇到严重问题以非零状态退出),`--fix`(应用安全的自动修复),`--no-shell`,`--strict`。
## 置信度 + 内联抑制
每个发现都有一个置信度级别:
| 置信度 | 含义 |
|------------|---------|
| `high` | 数据流已确认 —— 通过 AST 追踪输入至注入点 |
| `medium` | 带有验证逻辑的多信号正则表达式 |
| `low` | 纯正则表达式匹配 —— 启发式提示 |
```
vibeguard scan --min-confidence medium # hide low-confidence hints (default)
vibeguard scan --all # show everything
```
附带原因进行内联抑制:
```
const key = "sk_live_..."; // vibeguard-ignore[secret.stripe-live-key]: test fixture
```
## 基准测试
针对精选的 121 个文件语料库(90 个有漏洞 + 31 个无漏洞)进行测量。绝非虚荣指标。
## 总结
| 类别 | TP | FP | FN | 精确率 | 召回率 | F1 |
|----------|----|----|----|-----------|--------|----|
| injection | 43 | 5 | 6 | 89.6% | 87.8% | 88.7% |
| secrets | 19 | 7 | 2 | 73.1% | 90.5% | 80.9% |
| xss | 16 | 0 | 1 | 100.0% | 94.1% | 97.0% |
| path-traversal | 9 | 1 | 1 | 90.0% | 90.0% | 90.0% |
| ai-safety | 8 | 2 | 6 | 80.0% | 57.1% | 66.7% |
| **总计** | **95** | **15** | **16** | **86.4%** | **85.6%** | **86.0%** |
## 各类别详情
### injection
| 文件 | 规则 ID | 判定 |
|------|---------|---------|
| sql-concat.js | `code.sql-injection` | TP |
| sql-concat.js | `taint.sql-injection` | TP |
| sql-concat2.js | `code.sql-injection` | TP |
| sql-concat2.js | `taint.sql-injection` | TP |
| sql-concat3.js | `code.sql-injection` | TP |
| sql-template.js | `db.sql-template-literal` | TP |
| sql-template.js | `taint.sql-injection` | FN |
| sql-template2.js | `db.sql-template-literal` | FN |
| sql-template2.js | `taint.sql-injection` | TP |
| sql-template3.js | `db.sql-template-literal` | TP |
| sql-template3.js | `taint.sql-injection` | FN |
| sql-raw-rb.js | `code.sql-injection` | TP |
| sql-raw2.js | `db.sql-template-literal` | TP |
| sql-knex.js | `code.sql-injection` | TP |
| sql-knex.js | `mikroorm.identifier-from-request` | FP |
| sql-sequelize.js | `code.sql-injection` | TP |
| sql-fstring.py | `py.sql-injection` | TP |
| sql-fstring2.py | `py.sql-injection` | TP |
| sql-py-concat.py | `py.sql-injection` | FN |
| sql-sprintf.go | `go.sql-fmt-sprintf` | TP |
| sql-sprintf.go | `go.sql-injection` | FP |
| sql-sprintf2.go | `go.sql-fmt-sprintf` | TP |
| sql-sprintf2.go | `go.sql-injection` | FP |
| sql-kotlin.kt | `kotlin.sql-injection` | TP |
| sql-csharp.cs | `csharp.sql-injection` | TP |
| cmd-concat.js | `taint.command-injection` | TP |
| cmd-concat.js | `ast.command-injection` | TP |
| cmd-template.js | `taint.command-injection` | TP |
| cmd-template.js | `ast.command-injection` | TP |
| cmd-concat2.js | `taint.command-injection` | TP |
| cmd-concat2.js | `ast.command-injection` | TP |
| cmd-spawn.js | `taint.command-injection` | FN |
| cmd-py.py | `py.os-system` | TP |
| cmd-py2.py | `py.subprocess-shell-true` | TP |
| cmd-py3.py | `py.os-system` | TP |
| cmd-go.go | `go.command-injection` | TP |
| eval-input.js | `ast.eval-dynamic` | TP |
| eval-template.js | `ast.eval-dynamic` | TP |
| eval-template.js | `taint.code-injection` | FP |
| eval-new-function.js | `ast.function-constructor` | TP |
| eval-new-function.js | `ast.mass-assignment` | FP |
| nosql.js | `ast.nosql-injection` | TP |
| nosql2.js | `ast.nosql-injection` | TP |
| nosql3.js | `ast.nosql-injection` | TP |
| nosql-where.js | `ast.nosql-injection` | TP |
| proto-poll.js | `injection.prototype-pollution` | TP |
| proto-poll.js | `ast.mass-assignment` | TP |
| proto-poll2.js | `injection.prototype-pollution` | TP |
| proto-poll3.js | `injection.prototype-pollution` | TP |
| ssrf.js | `ast.ssrf` | TP |
| ssrf2.js | `ast.ssrf` | FN |
| ssrf2.js | `taint.ssrf` | TP |
| open-redirect.js | `web.open-redirect` | TP |
| open-redirect2.js | `taint.open-redirect` | TP |
### secrets
| 文件 | 规则 ID | 判定 |
|------|---------|---------|
| openai-key.js | `secret.openai-key` | TP |
| openai-key2.js | `secret.anthropic-key` | TP |
| github-token.js | `secret.github-token` | TP |
| github-token2.js | `secret.github-token` | TP |
| github-token2.js | `secret.high-entropy` | FP |
| stripe-key.js | `secret.stripe-live-key` | TP |
| stripe-key.js | `secret.generic-credential` | TP |
| stripe-key.js | `stripe.key-in-client` | FP |
| stripe-restricted.js | `secret.stripe-restricted-key` | TP |
| slack-token.js | `secret.slack-token` | TP |
| gitlab-token.js | `secret.gitlab-token` | TP |
| sendgrid-key.js | `secret.sendgrid-key` | TP |
| npm-token.js | `secret.npm-token` | TP |
| npm-token.js | `secret.high-entropy` | FP |
| gcp-key.js | `secret.gcp-api-key` | FN |
| private-key.js | `secret.private-key` | TP |
| aws-key.js | `secret.aws-access-key` | TP |
| mailgun-key.js | `secret.mailgun-key` | TP |
| mailgun-key.js | `secret.high-entropy` | FP |
| telegram-token.js | `secret.telegram-bot-token` | FN |
| resend-key.js | `secret.resend-key` | TP |
| conn-string.js | `secret.conn-string-password` | TP |
| conn-string.js | `secret.connection-string` | FP |
| generic-secret.js | `secret.generic-credential` | TP |
| docker-build-arg.js | `secret.docker-build-arg` | TP |
| docker-build-arg.js | `ai.key-in-url` | FP |
| env-secret.js | `secret.aws-secret-in-env` | TP |
| env-secret.js | `secret.high-entropy` | FP |
### xss
| 文件 | 规则 ID | 判定 |
|------|---------|---------|
| reflected-xss.js | `xss.reflected-response` | TP |
| reflected-xss.js | `taint.xss-reflected` | TP |
| reflected-xss2.js | `xss.reflected-response` | TP |
| reflected-xss2.js | `taint.xss-reflected` | TP |
| reflected-xss3.js | `xss.reflected-response` | TP |
| reflected-xss3.js | `taint.xss-reflected` | TP |
| reflected-xss4.js | `xss.reflected-response` | TP |
| reflected-xss4.js | `taint.xss-reflected` | TP |
| innerhtml.js | `injection.xss-angular-innerHTML` | TP |
| innerhtml.js | `taint.xss-dom` | TP |
| innerhtml2.js | `injection.xss-innerhtml-direct` | TP |
| innerhtml2.js | `taint.xss-dom` | TP |
| dangerously-html.jsx | `react.dangerous-html` | TP |
| dangerously-html2.jsx | `react.dangerous-html` | TP |
| dangerously-html2.jsx | `ai.llm-output-dom` | TP |
| vue-v-html.js | `injection.xss-vue-v-html` | FN |
| eval-llm-output.js | `ai.llm-output-dom` | TP |
### pathaversal
| 文件 | 规则 ID | 判定 |
|------|---------|---------|
| read-concat.js | `taint.path-traversal` | TP |
| sendfile.js | `taint.path-traversal` | TP |
| read-template.js | `taint.path-traversal` | TP |
| read-template.js | `ai.tool-broad-file-access` | TP |
| write-concat.js | `taint.path-traversal` | TP |
| unlink-concat.js | `taint.path-traversal` | TP |
| create-read-stream.js | `taint.path-traversal` | TP |
| append-file.js | `taint.path-traversal` | TP |
| path-join-template.js | `taint.path-traversal` | FN |
| path-join-template.js | `upload.filename-path-traversal` | TP |
| allowlist.js | `taint.path-traversal` | FP |
### ai-safety
| 文件 | 规则 ID | 判定 |
|------|---------|---------|
| user-in-system-prompt.js | `ai.user-input-in-system-prompt` | TP |
| llm-output-exec.js | `ai.llm-output-exec` | TP |
| llm-output-exec.js | `taint.command-injection` | TP |
| llm-output-exec.js | `ai.llm-output-shell` | FP |
| llm-output-exec.js | `ast.command-injection` | FP |
| agent-loop-no-cap.js | `ai.agent-loop-no-cap` | TP |
| model-id-user-input.js | `ai.model-id-injection` | TP |
| tool-result-injection.js | `ai.tool-result-injection` | FN |
| agent-memory-poison.js | `ai.memory-poisoning` | FN |
| tool-poisoning.js | `ai.tool-poisoning` | TP |
| tool-poisoning.js | `ai.mcp-description-injection-deep` | TP |
| prompt-extraction.js | `ai.prompt-extraction` | FN |
| llm-output-dom.js | `ai.llm-output-dom` | TP |
| agent-deploy.js | `ai.agent-can-deploy` | FN |
| agent-secrets.js | `ai.agent-can-access-secrets` | FN |
| model-id-template.js | `ai.model-id-injection` | FN |
## 方法论
- **True Positive (TP)**:预期规则在有漏洞的文件上触发。
- **False Positive (FP)**:在无漏洞文件上的任何发现,或在不安全文件上的意外规则触发。
- **False Negative (FN)**:在有漏洞的文件上未触发的预期规则。
- **Precision** = TP / (TP + FP)
- **Recall** = TP / (TP + FN)
- **F1** = 2 * (Precision * Recall) / (Precision + Recall)
生成时间:2026-07-12T18:25:03.049Z
## 命令
```
vibeguard scan [dir] # scan a project (auto-detects framework)
vibeguard scan --fix # scan + apply safe auto-fixes
vibeguard scan --all # show all findings including low-confidence
vibeguard auto [dir] # full protection (daemon + hooks + shell guard)
vibeguard auto --stop # turn off, restore backups
vibeguard fix [dir] # auto-fix 43 rule types
vibeguard pre-deploy [dir] # 13-gate deployment check
vibeguard mcp # MCP server (for AI client integration)
vibeguard guard "command" # check a shell command before running it
vibeguard install-hook # git pre-commit hook (blocks on critical)
vibeguard install-hook-post # PostToolUse hook (auto-scan AI edits)
```
## 隐私
VibeGuard 完全在你的机器上运行。默认情况下,没有遥测、没有分析、没有网络调用。
| 命令 | 联网? |
|---------|---------|
| `scan`, `fix`, `auto`, `mcp`, `install` | 从不 |
| `cve` (包名查找) | 自主选择开启,仅限 OSV.dev |
| `url` (请求头扫描) | 自主选择开启,仅限你提供的 URL |
runtime 拦截器增加了让数据泄露变得极其困难的防护措施 —— 它包装了 `fetch`、`http.request`、`child_process.exec` 和 `fs.readFileSync`,以阻止外发密钥、PII 和敏感文件访问。它不是一种沙箱逃逸预防层。
## 客观范围
VibeGuard 捕获 AI 编码工具遗留的机械性安全漏洞。它**不会**:
- 证明你的应用是安全或防泄漏的
- 在你的应用中端到端追踪个人数据
- 判断业务逻辑漏洞
- 取代涉及资金、身份验证或个人数据时的真正的安全审查
它能快速提高安全底线 —— 捕获 AI 工具默认创建的漏洞。上面的基准测试数据是客观真实的:86.0% 的 F1 分数意味着它会漏掉约 14% 的真实问题,并产生一些误报。运行 `npm run benchmark` 以进行复现。在依赖它之前,请阅读 `test/benchmark/benchmark-results.md` 中的各类别详细信息。
## 语言
JavaScript、TypeScript、Python、Go、Java、Ruby、PHP、C#、Rust、Kotlin、Swift、Bash、SQL、YAML。特定语言的规则受文件扩展名限制 —— Go 规则不会在 `.js` 文件上触发。
## CI/CD
```
vibeguard auto --ci # non-interactive, exit non-zero on critical
vibeguard init-ci # generate GitHub Actions workflow
vibeguard scan --output sarif # SARIF output for GitHub Code Scanning
```
包含适用于 GitLab CI、Jenkins、CircleCI、Azure Pipelines 的模板。
## 开发
```
npm install
npm test # 342 tests
npm run benchmark # precision/recall/F1
npm run counts # verify rule/tool counts match source
npm run lint # 0 errors
```
## 许可证
MIT。永久免费。无广告。无追踪。无数据收集。
## 由 Yagyesh Vyas 构建
发现 Bug?[提交一个 issue](https://github.com/yagyeshVyas/VibeGuard/issues)。 • 有疑问?[发起讨论](https://github.com/yagyeshVyas/VibeGuard/discussions)。
© 2026 Yagyesh Vyas。基于 MIT 许可证发布。
标签:CISA项目, DOE合作, MITM代理, StruQ, 人工智能安全, 代码安全, 合规性, 安全扫描, 对抗攻击, 开发安全工具, 敏感信息检测, 时序注入, 暗色界面, 漏洞枚举, 自动化payload嵌入, 自定义脚本, 错误基检测, 静态代码分析