tristandenyer/snytch-nextjs

GitHub: tristandenyer/snytch-nextjs

针对 Next.js 应用的密钥泄露检测工具,扫描编译后的 Bundle 和环境变量配置,在密钥暴露到生产环境前进行拦截。

Stars: 0 | Forks: 0

# @snytch/nextjs ![beta](https://img.shields.io/badge/status-beta-orange) [![npm version](https://img.shields.io/npm/v/@snytch/nextjs)](https://www.npmjs.com/package/@snytch/nextjs) [![npm downloads](https://img.shields.io/npm/dm/@snytch/nextjs)](https://www.npmjs.com/package/@snytch/nextjs) [![Node.js >=18](https://img.shields.io/node/v/@snytch/nextjs)](https://nodejs.org) [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE) 针对 Next.js 应用的 Bundle 扫描、密钥检测和环境变量暴露分析工具。 ## 为什么我们需要它 在 Next.js 中,即使环境变量没有 `NEXT_PUBLIC_` 前缀,如果它被共享模块、工具函数或在服务器和客户端都能渲染的组件导入,仍然可能最终进入客户端 Bundle。一旦进入生产环境,它就会出现在每位访客的浏览器、构建产物、CDN 缓存以及可能的 Git 历史记录中。 这个问题的规模超出了大多数团队的认知。根据 [GitGuardian 2026 年度密钥泄露现状报告](https://www.gitguardian.com/state-of-secrets-sprawl-report-2026),仅 2025 年公共 GitHub 仓库中就泄露了 2860 万个密钥,同比增长 34%。更令人担忧的是:2022 年泄露的密钥中有 64% 至今仍可被利用。 `@snytch/nextjs` 会扫描您编译后的 Bundle,检查 `.env` 文件,并对比您的环境配置,以便在这些问题进入生产环境之前将其拦截。 ## 环境要求 - Node.js 18 或更高版本 - 对于 `snytch scan`,需要一个已有构建产物(`.next/` 目录)的 Next.js 项目 ## 安装 `@snytch/nextjs` 最适合已有构建产物的成熟 Next.js 项目。请先运行 `npm run build` 生成 `.next` 目录,然后再安装并执行扫描。 ``` npm install -D @snytch/nextjs ``` ## 命令 ### `snytch scan` 扫描编译后的 Next.js Bundle,查找客户端 JavaScript 中泄露的密钥。 ``` # 基础扫描 — 将发现结果打印到终端 snytch scan # 生成 HTML 报告并在发现任何严重问题时使构建失败 snytch scan --report --fail-on critical # 使用自定义 .next 目录 snytch scan --dir ./apps/web/.next ``` | 选项 | 默认值 | 描述 | | --------------- | ----------- | ------------------------------------------------------------------------------------------------------------- | | `--dir` | `./.next` | `.next` 目录的路径 | | `--json` | off | 以 JSON 格式输出结果 | | `--report` | off | 在 `./snytch-reports/snytch-report.html` 生成 HTML 报告 | | `--fail-on` | `critical` | 退出代码阈值:`critical`、`warning` 或 `all` | | `--ai-provider` | `anthropic` | AI 根因分析提供商:`anthropic`(需要 `ANTHROPIC_API_KEY`)或 `openai`(需要 `OPENAI_API_KEY`)或 `none` | ![扫描报告显示检测到的密钥、严重级别、文件路径和 Git 来源](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/cfa96e7372181718.png) ### `snytch check` 检查 `.env` 文件中是否有看起来像密钥的 `NEXT_PUBLIC_` 变量。任何带有 `NEXT_PUBLIC_` 前缀的变量都会在构建时嵌入到客户端 Bundle 中,并发送给每个加载应用的浏览器。此命令会标记那些匹配已知密钥模式或熵值足够高以至于像是凭证的值。 ``` # 自动检测当前目录中的 .env 文件 snytch check # 检查特定文件 snytch check --env .env.local --env .env.production # 生成 HTML 报告 snytch check --env .env.local --report ``` | 选项 | 默认值 | 描述 | | ----------- | ----------- | --------------------------------------------------------------------- | | `--env` | 自动检测 | `.env` 文件的路径。可重复指定以检查多个文件。 | | `--json` | off | 以 JSON 格式输出结果 | | `--report` | off | 在 `./snytch-reports/snytch-check-report.html` 生成 HTML 报告 | | `--fail-on` | `critical` | 退出代码阈值:`critical`、`warning` 或 `all` | ### `snytch diff` 对比两个或多个 `.env` 文件中环境变量键的存在情况。“漂移”是指某个键存在于一个环境但不存在于另一个环境中。这就是密钥在生产环境中被错误配置的原因:某个键在开发期间被添加到 `.env.local`,但从未进入 `.env.production`;或者某个键从一个文件中删除了,但其他文件中没有删除。 `snytch diff` 仅比较键名,不比较值。它只会告诉您哪些内容缺失或不匹配,而不会显示具体的值。 ``` # 比较两个环境 snytch diff --env .env.staging --env .env.production # 比较三个环境 snytch diff --env .env.staging --env .env.production --env .env.local # 生成 HTML 报告并在发现任何差异(不仅是 serverOnly 键)时退出代码为 1 snytch diff --env .env.staging --env .env.production --report --strict ``` | 选项 | 默认值 | 描述 | | ---------- | ------- | ----------------------------------------------------------------- | | `--env` | 必填 | `.env` 文件的路径。必须至少提供两次。 | | `--json` | off | 以 JSON 格式输出结果 | | `--report` | off | 在 `./snytch-reports/snytch-diff-report.html` 生成 HTML 报告 | | `--strict` | off | 任何漂移均以退出代码 1 退出,而不仅仅是 `serverOnly` 键 | ![差异报告显示各 .env 文件之间的环境变量漂移,包含缺失或仅存在于某一环境中的键](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/b495945734181730.png) ### `snytch mcp` 在 stdio 传输层上启动 snytch MCP server。您无需直接运行此命令。您的编辑器会根据您提供的配置文件为您运行它。有关设置说明,请参阅下文的 [MCP Server](#mcp-server)。 ``` snytch mcp ``` ### `snytch demo` 使用涵盖所有严重级别和模式类型的模拟发现结果,运行所有三个命令(`scan`、`check` 和 `diff`)的完整端到端演示。输出与真实运行完全相同:相同的格式化器、相同的退出代码(1),并会将真实的 HTML 报告写入磁盘。 ``` snytch demo ``` 将在您的当前目录中生成三个报告文件: | 文件 | 内容 | | ----------------------------------------- | ---------------------------------------------- | | `snytch-reports/snytch-report.html` | Bundle 扫描发现结果,包含 Findings 和 AI RCA 选项卡 | | `snytch-reports/snytch-check-report.html` | `NEXT_PUBLIC_` 暴露发现结果 | | `snytch-reports/snytch-diff-report.html` | `.env` 文件间的环境变量漂移 | 要在 AI RCA 选项卡中查看真实的分析结果,请在运行前设置 API Key: ``` # Anthropic (Claude) ANTHROPIC_API_KEY=sk-ant-... snytch demo # OpenAI (GPT-4o) OPENAI_API_KEY=sk-... snytch demo --ai-provider openai ``` 演示完成后,系统将提示您删除生成的报告文件。 ![AI RCA 选项卡:Claude 或 GPT-4o 解释泄露了什么、何时引入、如何进入 Bundle 以及如何修复,并附带代码前后对比示例和编辑器提示](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/2348713b17181742.png) ## 功能特性 - 递归扫描 `.next/static/chunks` 中的 JavaScript 和 CSS 文件 - 检测 170 多种密钥模式,包括: - AWS 访问密钥、会话令牌和资源 ARN - Stripe、Square、PayPal、Braintree 和 Coinbase 密钥 - 数据库连接字符串(PostgreSQL、MySQL、MongoDB、Redis、Elasticsearch 等) - GitHub、GitLab 和 Bitbucket 令牌(经典版和细粒度版) - Slack、Discord、Twilio、SendGrid、Mailgun 和 Postmark 令牌 - 私钥(RSA、EC、DSA、OpenSSH、PGP) - JWT 令牌、OAuth 令牌和高熵 Bearer 令牌 - 云服务商密钥(Google Cloud、Azure、Firebase、Cloudflare、DigitalOcean、Vercel、Heroku) - AI 和 ML API 密钥(OpenAI、Anthropic、Cohere、Hugging Face、Replicate、Pinecone) - 认证服务商(Auth0、Okta) - 监控与可观测性(Datadog、New Relic、Sentry、Splunk、Grafana) - 针对未知密钥格式的高熵字符串启发式检测 - 设置 `--report` 后,通过 Claude (Anthropic) 或 GPT-4o (OpenAI) 进行 AI 根因分析 - 每项发现结果的 Git 来源(源文件 + 引入该结果的提交) - 包含每项发现详情和编辑器提示的 HTML 报告 - 用于编辑器集成(Cursor、Windsurf、Claude Desktop)的 MCP server ## MCP Server `@snytch/nextjs` 包含一个 [MCP](https://modelcontextprotocol.io) server,因此您可以直接在 Cursor、Windsurf 或 Claude Desktop 中运行扫描,而无需触碰终端。 配置完成后,您可以向 AI 助手发出如下指令: - “扫描我的 Bundle 是否有泄露的密钥” - “检查我的 .env 文件是否有暴露的 API 密钥” - “我的预发布环境和生产环境的 env 文件是否同步?” 助手会获取结构化的结果,并能在问题所在的文件中直接提出修复建议。密钥值绝不会通过 MCP 层传输 —— 传给 AI 的只有截断后的值。 ### 工具 | Tool | 描述 | | -------------- | ------------------------------------------------------ | | `snytch_scan` | 扫描 Next.js Bundle 中客户端 JS 泄露的密钥 | | `snytch_check` | 检查 `.env` 文件中危险的 `NEXT_PUBLIC_` 前缀使用情况 | | `snytch_diff` | 对比各 `.env` 文件中环境变量键的存在情况 | ### 工具模式 **`snytch_scan`** ``` // Input { "dir": "./.next" } // optional — defaults to /.next // Output { "findings": [...], // truncated values only, rca omitted "summary": { "scannedFiles": 12, "total": 2, "critical": 1, "warning": 1, "durationMs": 80 } } ``` **`snytch_check`** ``` // Input { "envFiles": [".env.local", ".env.production"] } // optional — auto-detects from cwd // Output { "findings": [...], "summary": { "scannedFiles": 2, "total": 1, "critical": 1, "warning": 0, "durationMs": 5 } } ``` **`snytch_diff`** ``` // Input { "envFiles": [".env.staging", ".env.production"] } // required — minimum 2 files // Output (key names only — values are never read into output) { "inSync": ["DATABASE_URL", "REDIS_URL"], "drift": [{ "key": "API_KEY", "presentIn": [".env.staging"], "missingFrom": [".env.production"] }], "onlyInOne": [{ "key": "DEV_FLAG", "file": ".env.staging" }] } ``` ### 编辑器设置 MCP server 在您编辑器打开的目录中运行,因此它会自动识别项目正确的 `.next` 目录和 `.env` 文件。无需配置路径。 #### Cursor 1. 打开(或创建)项目根目录下的 `.cursor/mcp.json`。 2. 添加以下内容: ``` { "mcpServers": { "snytch": { "command": "npx", "args": ["-y", "@snytch/nextjs", "mcp"] } } } ``` 3. 打开 Cursor 设置面板,转到 **MCP**,确认 `snytch` 显示绿色状态指示灯。 4. 打开聊天并尝试:_"Use snytch to scan my bundle for leaked secrets."_ #### Windsurf 1. 打开 `~/.codeium/windsurf/mcp_config.json`(如不存在则创建)。 2. 添加以下内容: ``` { "mcpServers": { "snytch": { "command": "npx", "args": ["-y", "@snytch/nextjs", "mcp"] } } } ``` 3. 打开 Windsurf MCP 面板并点击 **Refresh** 以加载新服务器。 4. 打开 Cascade 聊天并尝试:_"Check my .env files for exposed API keys."_ #### Claude Desktop 1. 打开您平台对应的 Claude Desktop 配置文件(如不存在则创建): | 平台 | 路径 | | ------- | ----------------------------------------------------------------- | | macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` | | Windows | `%APPDATA%\Claude\claude_desktop_config.json` | | Linux | `~/.config/Claude/claude_desktop_config.json` | 2. 添加以下内容: ``` { "mcpServers": { "snytch": { "command": "npx", "args": ["-y", "@snytch/nextjs", "mcp"] } } } ``` 3. 退出并重新启动 Claude Desktop。 4. 点击聊天输入框中的工具图标,确认列表中包含 `snytch_scan`、`snytch_check` 和 `snytch_diff`。 5. 尝试:_"Scan my Next.js bundle for secrets."_ ## 配置 在项目根目录创建 `snytch.config.js` 以自定义 snytch 的行为。由于 `@snytch/nextjs` 是一个 ESM 包,该文件必须使用 ESM 语法。 ``` // snytch.config.js export default { serverOnly: ['DATABASE_URL', 'STRIPE_SECRET_KEY', 'NEXTAUTH_SECRET'], failOn: 'critical', rca: { maxTokens: 2048, }, }; ``` | 选项 | 类型 | 描述 | | --------------- | ---------------------------------- | ------------------------------------------------------------------------------------ | | `serverOnly` | `string[]` | 绝不能暴露给客户端的变量名列表 | | `failOn` | `'critical' \| 'warning' \| 'all'` | 所有命令的默认退出代码阈值 | | `rca.maxTokens` | `number` | AI RCA 响应的最大 Token 数(默认:2048)。如果响应被截断,请增加此值。 | 当设置了 `serverOnly` 时: - `snytch check` 将标记任何出现在 `NEXT_PUBLIC_` 下的列表键 - 如果 `serverOnly` 键发生漂移,`snytch diff` 将在非严格模式下以退出代码 1 退出 - `snytch scan` 将检测 Bundle 中这些变量的字面值 ## CI/CD 集成 在 CI 中运行 snytch 可以在密钥进入生产环境之前将其拦截。当发现达到或超过指定严重级别时,scan 命令将以代码 1 退出,因此无需任何额外配置即可作为流水线门禁。 扫描前必须先构建 Bundle,因此请将扫描步骤在构建步骤之后。 ``` - name: Build run: npm run build - name: Scan bundle for secrets run: npx @snytch/nextjs scan --fail-on critical - name: Check NEXT_PUBLIC_ variables run: npx @snytch/nextjs check --fail-on critical ``` 如需同时检查 `.env` 文件间的环境变量漂移,请添加: ``` - name: Diff env files run: npx @snytch/nextjs diff --env .env.staging --env .env.production ``` ## 许可证 MIT
标签:AI 代码分析, CLI 工具, DevSecOps, Git 真实性, GNU通用公共许可证, HTML 报告, MCP 服务器, MITM代理, Node.js, Petitpotam, 上游代理, 云安全监控, 代码安全, 前端安全, 安全助手, 客户端打包, 构建安全, 漏洞枚举, 环境变量安全, 秘密检测, 自动化攻击, 软件供应链安全, 远程方法调用, 静态分析, 预防性安全