面向 AI 编码工具的安全检查点。它会审查 AI 助手写入的每个文件, 并在危险文件落盘之前将其阻止。
AI 编码助手(Claude Code、Codex……)编写代码的速度很快——包括那些处理密码、电子邮件、API 密钥或原始用户输入的代码。助手很容易在不考虑安全性的情况下,将这些数据直接写入数据库查询、shell 命令或 HTTP 响应中。
VibeGate 位于助手和你的文件系统之间。每当助手尝试写入或编辑文件时,VibeGate 都会先扫描新代码:
分析过程本身不涉及任何 LLM——它是快速、确定的静态分析,因此绝不会无中生有,也不会消耗你的 Token。
以下是 VibeGate 当前检查的所有内容:
| 检查项 | 捕获内容 | 结果 |
|---|---|---|
| 命令注入 | 未经处理的输入到达 shell 命令 | 阻止 |
| SQL 注入 | 未经处理的输入到达数据库查询 | 阻止 |
| NoSQL 注入 | 请求体直接用作数据库过滤器 | 阻止 |
| 模板注入 (SSTI) | 模板源本身(而不仅仅是其数据)来自用户输入 | 阻止 |
| 不安全的反序列化 | 不受信任的数据到达不安全的反序列化器(pickle、不安全的 YAML 等) | 阻止 |
| 路径遍历 | 未经处理的输入到达文件读取、写入或删除操作 | 阻止 |
| XXE | 不受信任的 XML 在启用外部实体的情况下被解析 | 阻止 |
| XSS | 未经处理的输入以原始 HTML 形式呈现 | 阻止 |
| 无限制文件上传 | 上传文件本身的名被用于构建保存路径 | 阻止 |
| SSRF | 服务器获取了一个未硬编码的 URL | 警告 |
| 开放重定向 | 重定向目标未硬编码 | 警告 |
| 批量赋值 | 整个请求体被传入模型构造函数或更新操作 | 警告 |
| 请求体中的敏感数据 | 从请求体中读取的电子邮件、密码、令牌等 | 警告 |
| URL/查询中的敏感数据 | 从查询字符串中读取的电子邮件、密码、令牌等 | 警告 |
| 请求头中的敏感数据 | 从请求头中读取的电子邮件、密码、令牌等 | 警告 |
| 来自用户输入的文件路径 | 变量(而非硬编码字符串)被用作文件路径 | 警告 |
| CLI 参数 | 数据来自命令行参数 | 警告 |
| 标准输入 | 数据来自 stdin | 警告 |
| 环境变量 | 数据来自环境变量 | 警告 |
| 未固定的 GitHub Action | 工作流使用了可变标签(@v4)而非提交 SHA | 警告 |
不安全的 pull_request_target | 工作流使用了 pull_request_target 触发器 | 警告 |
| 凭据日志记录 | 密码、API 密钥或令牌被传递给 print/console.log/记录器 | 警告 |
| 硬编码的秘密 | 变量名类似于秘密,被赋予一个看起来真实的字面值 | 警告 |
完整的最新列表位于 guidance.TECHNICAL_RISKS 和 formatter.BLOCKING_CATEGORIES 中,以防此表出现偏差。
┌───────────────────────────────┐
│ 你要求 Claude Code 写入 │
│ 或编辑某个文件 │
└───────────────┬───────────────┘
│
▼
┌───────────────────────────────┐
│ Claude Code 尝试保存文件 │
│ (Write/Edit 工具) │
└───────────────┬───────────────┘
│
▼
┌───────────────────────────────┐
│ VibeGate 钩子 │
│ (自动运行,在文件保存之前) │
└───────────────┬───────────────┘
│
使用 Semgrep 扫描新代码
│
┌─────────────────────┼─────────────────────┐
│ │ │
▼ ▼ ▼
┌────────────────────┐ ┌────────────────────┐ ┌──────────────────────┐
│ 未发现风险输入 │ │ 发现风险输入, │ │ 风险输入到达关键 │
│ │ │ 但风险较低 │ │ 接收器 (SQL/命令/ │
│ │ │ (例如显示在 │ │ RCE/模板注入) │
│ │ │ HTTP 响应中) │ │ │
└─────────┬──────────┘ └─────────┬──────────┘ └───────────┬──────────┘
│ │ │
▼ ▼ ▼
文件已保存, 文件已保存, 文件未保存。
无任何显示。 终端中显示警告, Claude Code 看到
包含风险及修复方法。 阻止原因,并被告知
需要修复什么。
简而言之:安全代码无干扰通过;有风险但可生存的代码在保存时附带警告;而距离 SQL 注入、命令注入或远程代码执行仅一步之遥的代码,在到达磁盘之前就会被阻止。
如果 VibeGate 本身遇到意外错误,它总是允许写入通过——钩子中的错误绝不应成为阻碍你工作的理由。
每个警告和阻止还附带一条明确指令,指示 Claude Code 在其回复中将发现的结果告知你,而不仅仅是静默修复。这正是 VibeGate 的活动在对话中可见的原因,而不仅仅是在你特意查看的终端日志中。
| VibeGate 看到的内容 | 结果 |
|---|---|
| 无用户输入,或尚不支持的语言 | 文件正常保存,无显示 |
| 发现用户输入,但风险中等(例如开放重定向、批量赋值) | 文件保存,终端显示警告 + 指导 |
| 用户输入未处理即流入关键接收器(SQL/NoSQL 查询、shell 命令、模板引擎、反序列化器、XML 解析器、文件路径、上传文件名或原始 HTML 输出) | 文件未保存——Claude Code 被告知原因 |
有关每个检查项哪些会阻止、哪些仅警告的完整分类,请参阅上面的“它解决了什么问题?”表格。
目前 VibeGate 支持 Python、JavaScript/TypeScript、Go、Java、PHP 和 Ruby,并可接入 Claude Code 和 Codex。更多语言和工具可在不触及核心逻辑的情况下添加。
它还会检查 GitHub Actions 工作流文件中的两个常见 CI/CD 供应链错误:使用了可变标签(@v4)而非提交 SHA 的 Action,以及不安全的 pull_request_target 触发器。两者均发出警告而非阻止,因为它们属于加固检查,而非活跃漏洞的证据。
以下是 Claude Code 从零构建 RSS 阅读器应用程序的真实录制,VibeGate 全程运行。注意观察 Claude Code 何时停下来,明确说明 VibeGate 标记了哪些内容及其原因,然后继续——包括在抓取 Feed 的代码中发现一个真实的 SSRF 风险,并当场修复。
这里是第二个示例,以静态图片形式展示:Claude Code 正在构建一个允许用户上传照片并查看其详细信息的应用程序。VibeGate 注意到文件名和其他文件详情稍后会在屏幕上显示,并警告这可能会被用来向页面注入恶意代码(这称为 XSS)。Claude Code 调整了代码,使信息能够安全地显示。
在这两种情况下,都没有无故阻止任何内容,也无需逐行阅读代码来发现问题。VibeGate 在文件写入的那一刻就捕获了问题,AI 则在现场修复了它。
有两种方法可以让 AI 助手编写更安全的代码。一种方法是在对话开始前加载一套关于安全编码的大指令集,例如涵盖 SQL 注入、XSS、密码处理、文件上传等方面的清单。另一种方法就是 VibeGate 所做的:在文件写入时自动检查代码,并且只在真正出现问题时才发出提示。
第一种方法会在每条消息上消耗 Token,无论是否必要。一个覆盖多个风险类别的典型安全编码清单很容易增加几千个 Token。如果 AI 助在一次会话中编写 50 个文件,并且该清单每次都被重新加载或保留在上下文中,那么你可能会为通常不适用于当前正在写入文件的建议支付超过十万个 Token。一个登录页面和一个简单的颜色常量文件不需要相同的警告,但加载的清单无法预先区分它们。
VibeGate 则反过来。它对每个没有风险模式的文件保持沉默,不产生额外成本。只有当它发现某些问题时——比如用户输入流入数据库查询——它才会添加一个简短的、针对该问题的具体说明,通常只是完整清单的一小部分。因此,无论文件如何,你都不需要支付固定的 Token 成本,只在真正需要关注的文件上支付较小的成本,而且该成本精确针对发现的问题,而不是一场通用的安全讲座。
这也使得指导更加可靠。要求 AI 助手在编写一百行代码时“注意安全性”可能会漏掉众多风险行中的一行。门控不会疲劳或分心:它每次都会使用相同的固定规则检查每一次写入。
一次性安装——这也会拉取 VibeGate 依赖的 Semgrep:
pipx install git+https://github.com/theMiddleBlue/vibegate
然后在你想要保护的任何项目中开启:
cd your-project
vibegate on # 在此处开启(之后重新加载 Claude Code)
vibegate status # 检查该项目是否已开启
vibegate off # 在此处关闭
vibegate on 会将 Write|Edit|MultiEdit 的 PreToolUse 钩子添加到该项目的 .claude/settings.local.json 中。它是按项目作用域的,因此在一个仓库中开启不会影响其他仓库。
Claude Code 以 vibegate run --host claude_code 的方式运行该钩子——无需绝对路径,因此即使你重新安装或移动文件,它也能继续工作。
vibegate status 还会显示 VibeGate 在该项目中实际捕获的运行日志——每次警告和阻止,附带文件、行号和类别——让你能够看到其随时间推移的活动,而不仅仅是它是否已开启:
$ vibegate status
█ █ █████ ████ █████ ████ ███ █████ █████
...
● VibeGate 已启用,位于 .claude/settings.local.json
最近活动(最近 2 条记录,最多显示 2 条,最近优先):
2026-07-02T17:35:48+00:00 ⛔ 已阻止 server.py:3 EXEC_INPUT (FREE_TEXT)
2026-07-02T17:35:46+00:00 ⚠ 已警告 app.py:2 HTTP_BODY (EMAIL)
此日志位于项目根目录的 .vibegate/activity.jsonl 中——请将其添加到 .gitignore,这是本地开发者状态,不应提交。
VibeGate 按以下顺序确定它正在与哪个宿主通信:显式的 --host <name> 标志,然后是 VIBEGATE_HOST 环境变量,接着是从传入载荷中自动检测,最后回退到 claude_code。
如果 VibeGate 标记了你明确决定安全的内容,在相同行添加 vibegate-ignore 注释——它适用于任何注释语法(#、//……),因为 VibeGate 只查找文本:
query = f"SELECT * FROM users WHERE id = {user_id}" # vibegate-ignore
要仅抑制特定类别而非该行的所有内容,可以在冒号后列出它们(匹配技术类别或语义类型,逗号分隔,不区分大小写):
query = f"SELECT * FROM users WHERE id = {user_id}" # vibegate-ignore: DB_QUERY
src/vibegate/
├── hook.py # 入口点
├── cli.py # on/off/status 命令 + ASCII 标题
├── activity_log.py # 将警告/阻止持久化到 .vibegate/activity.jsonl
├── colors.py # 共享 ANSI 颜色代码(报告 + CLI 标题)
├── core.py # 与宿主无关的管道
├── models.py # InputEvent / ClassifiedFinding / AnalysisResult
├── semgrep_runner.py # 作为子进程运行 Semgrep(故障安全)
├── classifier.py # 将 Semgrep 规则 → 类别,变量名 → 数据类型
├── guidance.py # 静态的风险/修复说明
├── formatter.py # 将结果转换为终端报告 + 宿主上下文
├── adapters/ # 基类、claude_code、codex + 一个小型注册表
└── rules/ # Semgrep 规则——每种语言一个文件(Python、JS/TS、
# Go、Java、PHP、Ruby)加上一个通用占位符
管道本身(core.py)从不直接与特定宿主通信——所有宿主的输入/输出都位于 adapters/ 中,因此添加新宿主无需修改分析逻辑。
semgrep --validate --config src/vibegate/rules/ # 检查规则是否有效
pytest tests/ # 单元 + 集成测试
要在没有 Claude Code 的情况下端到端查看效果:
python3 -c 'import json; print(json.dumps({"tool_name":"Write","tool_input":{"file_path":"/tmp/t.py","new_content":"email = request.json.get(\"email\")"}}))' \
| python3 src/vibegate/hook.py --host claude_code
rules/<lang>-user-input.yaml,在 classifier.RULE_TO_TECHNICAL 中注册新规则 ID,并在 core.EXT_TO_LANGUAGE 中映射文件扩展名。classifier.VARNAME_TO_SEMANTIC 添加关键字,并在 guidance.SEMANTIC_GUIDANCE 中添加说明。RULE_TO_TECHNICAL 中添加条目,以及在 guidance.TECHNICAL_RISKS 中添加卡片。adapters/ 下添加适配器,并在 adapters/__init__.py 中注册它。codex 适配器是早期的、尽力而为的映射。在依赖它阻止任何内容之前,请根据你的 Codex 版本仔细检查其事件契约。"requires login" 而非实际匹配的行,因此分类器根据行号从文件内容中自行重建片段。Edit/MultiEdit,claude_code 适配器从磁盘中重建完整的编辑后文件,以便污染的来源和接收器(由不同编辑引入)仍然连接——但仅报告编辑实际触及的行上的发现。如果接收器已存在,而后续编辑仅添加了到达该接收器的污染来源,则不会捕获(接收器所在行不是新编辑的一部分)。此重建是 Claude Code 特有的;codex 适配器尚未实现。