关于 sast-hardcodedsecrets
用于查找公开可访问代码中硬编码机密的安全审查 skill。它区分客户端可访问代码与仅后端位置,再分批验证候选项并汇总结果;运行前需要 `sast/architecture.md`。
主要功能
- 01发现机密候选项
- 02评估公开代码中的暴露
- 03分批验证候选项
- 04汇总分析结果报告
适用场景
- 01检查前端构建产物中的凭据
- 02审查移动端代码中的嵌入机密
- 03区分客户端暴露项与仅后端值
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ utkusen/ sast-skills --skill sast-hardcodedsecrets安装后在 Claude Code 中输入/sast-hardcodedsecrets确认已加载。
详细介绍
公开代码中的硬编码密钥检测
你正在进行一项专项安全评估,以查找公开可访问代码中暴露的硬编码敏感数据。此技能采用包含子 Agent 的三阶段方法:侦察(查找所有潜在的密钥候选项)、分批验证(以每批 3 个的并行批次确认每个候选项是否为公开可访问代码中的真实密钥),以及合并(将各批次报告整合到一个文件中)。
前提条件:必须存在 sast/architecture.md。如果不存在,请先运行分析技能。
什么是公开代码中的硬编码密钥
硬编码密钥是直接以字符串字面量形式嵌入源代码中的敏感凭据,例如 API 密钥、访问令牌、私钥、密码、签名密钥和数据库连接字符串。
此技能专门关注最终出现在公开可访问代码中的密钥,也就是说,攻击者无需任何服务器端访问权限即可提取这些密钥。硬编码在后端服务器代码中的密钥属于不良实践,但外部攻击者无法通过检查已部署的应用直接利用它。硬编码在前端 JavaScript 或移动应用二进制文件中的密钥则可以被直接提取。
核心问题:外部攻击者能否在不访问服务器的情况下,从已部署的应用中获取此密钥?
应报告的内容(公开可访问代码)
部署后,攻击者可以访问以下代码路径:
- 前端 JavaScript/TypeScript — 在浏览器中运行的任何
.js、.ts、.jsx、.tsx文件。这包括:- React、Angular、Vue、Svelte 组件和页面
- Next.js 客户端组件(含有
"use client"的文件,或app/下不含"use server"的文件) - Nuxt.js 页面和客户端插件
public/、static/或assets/目录中的原生 JS- Webpack/Vite/Rollup 入口文件及其导入的模块
- 客户端入口文件导入的任何文件(即使它位于
utils/或lib/文件夹中)
- 移动应用代码 — 可通过逆向工程提取(反编译 APK、检查 IPA):
- Android:Java/Kotlin 源文件
- iOS:Swift/Objective-C 源文件
- React Native:JavaScript 包
- Flutter:Dart 源文件
- Xamarin:C# 源文件
- 提供给客户端的 HTML 文件和模板 — 内联
<script>块、data-属性、meta 标签 - 客户端配置文件 —
public/、static/、assets/、www/目录中的文件 - Electron/桌面应用源代码 — 可从 ASAR 归档中提取
- WebAssembly 源代码/配套 JS — JS 胶水代码中的密钥,或可从 WASM 中提取的密钥
不应报告的内容(仅限后端的代码)
请勿标记以下位置中的密钥 — 它们无法公开访问:
- 服务端应用代码 — Express 路由处理程序(仅服务端)、Django 视图、Flask 路由、Spring 控制器、Rails 控制器、Go HTTP 处理程序、PHP 控制器 — 仅在服务器上运行的代码
- 服务端 API 路由文件 — Next.js
app/api/路由、Nuxt 服务端路由、SvelteKit+server.ts文件 - 环境文件 —
.env、.env.local、.env.production(除非以静态方式提供) - 服务端配置 —
config/database.yml、settings.py、application.properties、appsettings.json - CI/CD 流水线文件 —
.github/workflows/、Jenkinsfile、.gitlab-ci.yml - Docker/基础设施文件 —
Dockerfile、docker-compose.yml、Kubernetes 清单 - 后端工具/服务文件 — 仅由服务端代码导入的文件
- 测试文件 — 测试样例和测试配置(除非测试文件会随应用一起发送给客户端)
- 迁移文件 — 数据库迁移
区分前端与后端
这一点至关重要,需要了解项目架构:
Next.js:app/ 下带有 "use client" 指令或未带有 "use server" 的文件属于客户端组件。app/api/ 下的文件仅在服务端运行。pages/api/ 下的文件仅在服务端运行。pages/ 下非 api 的文件会在服务端和客户端渲染——其中的机密信息会暴露。next.config.js 仅在服务端运行,但 NEXT_PUBLIC_* 环境变量会嵌入客户端代码包。
Nuxt.js:pages/、components/、composables/ 下的文件可由客户端访问。server/ 下的文件仅在服务端运行。
React (CRA/Vite):src/ 中的所有内容都会打包到客户端。REACT_APP_* 和 VITE_* 环境变量会嵌入客户端构建产物。
Angular:src/ 中的所有内容都会打包到客户端。
Vue (Vite):src/ 中的所有内容都会打包到客户端。VITE_* 环境变量会嵌入客户端。
Express/Fastify/Koa:所有内容都在服务端运行,除非从 public/ 或 static/ 目录提供静态文件。
Django/Flask:Python 代码在服务端运行。模板在服务端渲染(模板上下文中的机密信息不会传到客户端,除非明确渲染进 JS)。static/ 中的静态文件可由客户端访问。
Rails:Ruby 代码在服务端运行。app/assets/javascripts/ 或 app/javascript/ 中的资源可由客户端访问。
移动应用:所有源代码都应视为可通过逆向工程公开获取。
要查找的机密信息类型
高置信度模式(可通过正则表达式识别)
这些模式具有明显特征,因此可以高置信度地识别:
| 机密类型 | 模式 |
|---|---|
| AWS Access Key ID | AKIA[0-9A-Z]{16} |
| AWS Secret Access Key | 靠近 AKIA 密钥的 40 字符 base64 字符串 |
| Google API Key | AIza[0-9A-Za-z\\-_]{35} |
| Google OAuth Client Secret | GOCSPX-[0-9A-Za-z\\-_]{28} |
| GitHub Personal Access Token | ghp_[0-9A-Za-z]{36}, github_pat_[0-9A-Za-z_]{82} |
| GitHub OAuth App Secret | gho_[0-9A-Za-z]{36} |
| GitLab Personal Access Token | glpat-[0-9A-Za-z\\-_]{20} |
| Slack Bot/User Token | xoxb-[0-9A-Za-z\\-]+, xoxp-[0-9A-Za-z\\-]+ |
| Slack Webhook URL | hooks.slack.com/services/T[A-Z0-9]+/B[A-Z0-9]+/[A-Za-z0-9]+ |
| Stripe Secret Key | sk_live_[0-9A-Za-z]{24,} |
| Stripe Publishable Key | pk_live_[0-9A-Za-z]{24,}(可公开密钥专为客户端使用而设计——除非与秘密密钥同时出现,否则跳过) |
| Twilio Account SID + Auth Token | AC[0-9a-f]{32}(SID),附近还有 32 位十六进制认证令牌 |
| SendGrid API Key | SG\.[0-9A-Za-z\\-_]{22}\.[0-9A-Za-z\\-_]{43} |
| Mailgun API Key | key-[0-9a-zA-Z]{32} |
| Firebase Config | 配置对象中同时包含 apiKey、authDomain、projectId——仅当其中包含服务端/管理员密钥,而非标准客户端配置时才标记 |
| Private RSA/EC/SSH Key | `-----BEGIN (RSA |
| JWT Secret / Signing Key | 赋给 JWT_SECRET、jwt_secret、signingKey、HMAC_KEY 等变量的字符串 |
| 带密码的数据库连接字符串 | postgresql://user:pass@、mysql://user:pass@、mongodb://user:pass@、redis://:pass@ |
| 通用 API Key 赋值 | 名为 *api_key*、*apiKey*、*API_KEY*、*secret*、*SECRET*、*token*、*TOKEN*、*password*、*PASSWORD* 的变量,被赋值为看起来像真实凭据的字符串字面量 |
| Heroku API Key | Heroku 上下文中的 [0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12} |
| Azure Storage Key | 赋给存储帐户密钥变量的约 88 字符 base64 字符串 |
| OpenAI API Key | sk-[A-Za-z0-9]{48} 或 sk-proj-[A-Za-z0-9\\-_]{100,} |
| Anthropic API Key | sk-ant-[A-Za-z0-9\\-_]{90,} |
变量名称模式(需要检查值)
搜索名称符合以下模式的变量/常量,并检查赋值是否看起来像真实凭据:
api_key、apiKey、API_KEY、ApiKeysecret、SECRET、secret_key、secretKey、SECRET_KEYaccess_token、accessToken、ACCESS_TOKENauth_token、authToken、AUTH_TOKENprivate_key、privateKey、PRIVATE_KEYpassword、PASSWORD、passwd、PASSWDclient_secret、clientSecret、CLIENT_SECRETsigning_key、signingKey、SIGNING_KEYencryption_key、encryptionKey、ENCRYPTION_KEYbearer_token、BEARER_TOKENcredentials、CREDENTIALSconnection_string、connectionString、DATABASE_URL
哪些不是真正的密钥(可忽略的误报)
- 占位值:
"your-api-key-here"、"TODO"、"xxx"、"changeme"、"REPLACE_ME"、"INSERT_KEY"、"<api_key>"、"dummy"、"test"、"example"、"sample"、"placeholder" - 空字符串:
""、'' - 环境变量引用:
process.env.API_KEY、os.environ["SECRET"]、ENV["KEY"]——这些会在运行时从环境中读取,而非硬编码 - 公钥:公钥(而非私钥)就是用于共享的,不属于密钥
- 可发布/公开 API 密钥:Stripe
pk_test_*、pk_live_*;Firebase 客户端配置apiKey(专为客户端使用而设计);Google Maps 客户端密钥(受 HTTP 引荐来源限制) - 测试/开发密钥:
sk_test_*(Stripe 测试密钥)、明确命名为测试夹具的文件中的密钥 - 类型定义/接口:TypeScript
interface Config { apiKey: string }——不包含实际值 - 文档字符串:说明密钥形式的注释
- 哈希值:不属于密钥的 SHA256/MD5 哈希(例如内容哈希、校验和)
- 构建时常量:版本字符串、构建 ID、提交哈希
执行
此技能分三个阶段使用子 Agent 运行。将 sast/architecture.md 的内容作为上下文传递给所有子 Agent。
阶段 1:侦察 — 查找潜在机密
启动一个子 Agent,并提供以下指示:
目标:查找代码库中所有以字符串字面量形式出现的硬编码机密(API 密钥、访问令牌、私钥、密码、签名机密、连接字符串)。将结果写入
sast/hardcodedsecrets-recon.md。背景:你将获得项目架构摘要。利用它了解技术栈、项目结构,以及哪些文件属于前端或后端。
搜索内容:
扫描整个代码库。在此阶段,无论潜在机密位于前端还是后端代码中,都要全部标记——筛选将在阶段 2 进行。
- 高置信度正则表达式模式——搜索以下特征鲜明的格式:
- AWS 密钥:
AKIA[0-9A-Z]{16}- Google API 密钥:
AIza[0-9A-Za-z\-_]{35}- GitHub 令牌:
ghp_、github_pat_、gho_、ghs_- Slack 令牌:
xoxb-、xoxp-、xoxa-、xoxr-- Stripe 机密密钥:
sk_live_、sk_test_- SendGrid 密钥:
SG\.- OpenAI 密钥:
sk-后跟 48 个或更多字母数字字符- Anthropic 密钥:
sk-ant-- 私钥标头:
-----BEGIN.*PRIVATE KEY------ 包含内嵌密码的连接字符串:
://[^:]+:[^@]+@- 变量赋值模式——搜索名称与机密相关、且被赋予字符串字面量值的变量:
- 搜索如下模式:
apiKey = "..."、api_key = '...'、API_KEY: "..."、secret: "..."、token = "..."、password = "..."、client_secret = "..."- 包含所有大小写命名惯例:camelCase、snake_case、SCREAMING_SNAKE_CASE、PascalCase
- 检查 JS/TS 对象、JSON 文件、YAML/TOML 配置、Python 字典以及类似环境变量的配置
- 符合已知密钥格式的内嵌字符串字面量:
- 赋给身份验证相关变量的长随机字母数字字符串(32 个或更多字符)
- 身份验证上下文中的 Base64 编码字符串
- 用作密钥或机密的十六进制字符串(64 个或更多字符)
- 用作 API 密钥或机密的 UUID
侦察时跳过以下内容:
- 环境变量读取:
process.env.*、os.environ[*]、ENV[*]、System.getenv(*)——这些不是硬编码值- 没有值的类型定义:
apiKey: string、type Config = { secret: string }- 明显的占位符:
"your-key-here"、"TODO"、"xxx"、"changeme"、"REPLACE_ME"、"<api_key>"、"dummy"、"test-key"、"example"、"sample"、空字符串- 仅描述或记录机密的注释
- 公钥(非私有的加密密钥)
- 用作校验和或内容标识符的哈希值
.git/、node_modules/、vendor/、venv/、__pycache__/、dist/、build/目录中的文件输出格式——写入
sast/hardcodedsecrets-recon.md:# 硬编码机密侦察:[项目名称] ## 摘要 找到 [N] 个潜在的硬编码机密候选项。 ## 候选项 ### 1. [描述性名称,例如“API 配置中的 AWS 访问密钥”] - **文件**:`path/to/file.ext`(第 X-Y 行) - **机密类型**:[AWS 密钥 / Google API 密钥 / 通用 API 密钥 / 私钥 / 密码 / JWT 机密 / 连接字符串 / 等] - **变量/上下文**:[机密出现处的变量名或上下文] - **检测方法**:[正则匹配 / 变量名称模式 / 内嵌字面量] - **代码片段**:[显示包含机密的行——对实际值的中间部分进行脱敏,例如:"AKIA****EXAMPLE" 或 "sk_live_****abcd"]
[对每个候选项重复以上内容]
阶段 1 之后:继续之前检查候选项
阶段 1 完成后,读取 sast/hardcodedsecrets-recon.md。如果侦察结果中没有候选项(摘要显示“Found 0”,或者“Candidates”部分为空或不存在),则完全跳过阶段 2 和阶段 3。改为将以下内容写入 sast/hardcodedsecrets-results.md,然后停止:
# Hardcoded Secrets Analysis Results
No vulnerabilities found.
只有阶段 1 找到至少一个候选项时,才继续阶段 2。
阶段 2:验证——确认公开代码中的真实密钥(分批处理)
阶段 1 完成后,读取 sast/hardcodedsecrets-recon.md,并将候选项拆分为每批最多 3 个候选项。并行启动每批一个子 Agent。每个子 Agent 只验证分配给自己的候选项,并将结果写入自己的批次文件。
分批流程(由你(编排者)执行,而不是子 Agent):
- 读取
sast/hardcodedsecrets-recon.md,统计编号候选项部分(### 1.、### 2. 等)的数量。 - 将它们拆分为每批最多 3 个候选项。例如,8 个候选项 -> 3 批(1-3、4-6、7-8)。
- 从侦察文件中提取每批候选项部分的完整文本。
- 并行启动所有批次子 Agent,并仅向每个子 Agent 提供分配给它的候选项。
- 每个子 Agent 将结果写入
sast/hardcodedsecrets-batch-N.md,其中 N 是从 1 开始的批次编号。
向每个批次子 Agent 提供以下说明(替换为该批次对应的值):
目标:验证以下硬编码密钥候选项。对每一项,确定 (1) 是否为真实密钥,以及 (2) 是否位于可公开访问的代码中。将结果写入
sast/hardcodedsecrets-batch-[N].md。分配给你的候选项(来自侦察阶段):
[在此粘贴分配给你的候选项章节的完整文本,并保留原始编号]
背景:你将获得项目架构摘要。请利用它了解技术栈、前后端分离情况、构建流程,以及哪些目录包含客户端代码和服务器端代码。
对于每个候选项,请回答两个问题:
问题 1:这是真实密钥吗?
检查该值是否为真实凭据,而非误报:
- 该字符串是否具有真实密钥/令牌的熵和格式?(真实 API 密钥通常包含 20 个以上的随机字符)
- 它是否为已知占位符或示例值?(“your-key-here”、“changeme”、“test”、“example”、“TODO”、“xxx”、“REPLACE_ME”等)
- 它是否为测试/开发密钥?(Stripe
sk_test_*、沙盒凭据、测试夹具中的密钥)- 它是否为按设计公开/可发布的密钥?(Stripe
pk_live_*、Firebase 客户端apiKey、Google Maps 浏览器密钥)- 它是否实际上是被误识别的环境变量引用?
- 它是否为哈希、校验和或非密钥标识符?
如果该值不是真实密钥,请将其归类为 Not Vulnerable 并说明原因。
问题 2:它是否位于可公开访问的代码中?
判断外部攻击者能否从已部署的应用中提取该密钥:
可公开访问(报告这些项):
- 在浏览器中运行的前端 JavaScript/TypeScript(React、Angular、Vue、Svelte 组件/页面)
- Next.js 客户端组件(包含
"use client"的文件或客户端渲染的页面)- Nuxt.js
pages/、components/、客户端plugins/- 任何由客户端入口点导入的
.js/.ts文件(追踪导入链)- 直接提供服务的
public/、static/、assets/、www/目录中的文件- 包含内嵌
<script>块的 HTML 文件- 移动应用源代码——Android(Java/Kotlin)、iOS(Swift/Objective-C)、React Native JS、Flutter Dart、Xamarin C#——所有移动端代码都可通过逆向工程提取
- Electron 应用源代码(可从 ASAR 中提取)
- 内嵌在 JavaScript 中的客户端配置对象(例如 Firebase 配置、分析工具初始化代码)
不可公开访问(不要报告):
- 服务器端路由处理程序(Express、Django、Flask、Rails、Spring、Go、PHP 控制器)
- 服务器端 API 路由(Next.js
app/api/、Nuxtserver/、SvelteKit+server.ts)- 仅由服务器端代码导入的后端服务、中间件、实用工具
.env文件、服务器配置文件、Docker/CI 文件- 不会发送给客户端的测试文件和夹具
- 数据库迁移
- 构建脚本和工具
如何判断文件是否为客户端代码:
- 检查文件路径——它是否位于客户端目录下?(CRA/Vite React 中的
src/、Next.js 中的pages/、Angular 中的app/、Vue 中的src/)- 追踪导入链——该文件是否由客户端入口点直接或间接导入?
- 检查仅限服务器端的标记——
"use server"指令,或位于api/、server/目录中的文件- 查看
sast/architecture.md,了解项目的前后端分离模式- 对于有歧义的情况(例如共享实用工具文件),请谨慎处理——如果该文件可能被打包到客户端,就视为可公开访问
如果密钥不在可公开访问的代码中,请将其归类为 Not Vulnerable 并说明原因(例如:“仅限服务器端——Express 路由处理程序”)。
分类:
- Vulnerable:确认是真实密钥,且确认位于可公开访问的代码中。攻击者可以从已部署的应用中提取该密钥。
- Likely Vulnerable:看起来是真实密钥,且文件可能可由客户端访问,但无法完全确认一项或两项条件(例如导入链有歧义,或无法确定该值是否为生产环境密钥)。
- Not Vulnerable:要么不是真实密钥(占位符、测试密钥、公开密钥),要么不在可公开访问的代码中(仅限后端)。
- Needs Manual Review:无法确定该值是否为真实密钥,或文件是否会到达客户端——需要人工判断。
输出格式——写入
sast/hardcodedsecrets-batch-[N].md:# 硬编码密钥批次 [N] 结果 ## 发现项 ### [VULNERABLE] 描述性名称 - **文件**:`path/to/file.ext`(第 X-Y 行) - **密钥类型**:[AWS 密钥 / Google API 密钥 / 等] - **暴露路径**:[攻击者如何提取——例如“通过 Webpack 打包到客户端 JS,可在浏览器 DevTools 的 Sources 标签页中查看”或“嵌入 Android APK,可通过 `apktool d app.apk` 提取”] - **问题**:[清晰描述——例如“硬编码在 React 组件中的 AWS 访问密钥会被打包到浏览器端”] - **影响**:[攻击者利用该密钥可以做什么——例如“完全访问 AWS S3 存储桶,可能导致数据外泄”、“代表组织通过 SendGrid 发送邮件”、“通过 API 访问用户数据”] - **证据**:[部分遮蔽密钥值的代码片段]
- **修复建议**:[将密钥移至服务器端环境变量。如果客户端需要调用此 API,请通过后端代理。对于移动应用,请使用后端代理或 OAuth 流程,而不是嵌入密钥。] - **验证步骤**:[如何确认此发现:
- 对于 Web 应用:“打开浏览器 DevTools > Sources > 在打包后的 JS 文件中搜索 ‘AKIA’”
- 对于移动应用:“运行
apktool d app.apk并 grep 搜索密钥模式”- 对于 Electron:“提取 ASAR 归档并搜索密钥”]
### [LIKELY VULNERABLE] 描述性名称 - **文件**:`path/to/file.ext`(第 X-Y 行) - **密钥类型**:[类型] - **暴露路径**:[推测该密钥如何到达客户端] - **问题**:[不确定之处] - **风险**:[为什么仍然存在风险] - **证据**:[代码片段]
- **修复建议**:[修复建议] ### [NOT VULNERABLE] 描述性名称 - **文件**:`path/to/file.ext`(第 X-Y 行) - **原因**:[例如:“占位符——‘your-api-key-here’”或“仅限服务器端——Django 视图,不会到达客户端”或“Stripe 可发布密钥——专为客户端使用而设计”] ### [NEEDS MANUAL REVIEW] 描述性名称 - **文件**:`path/to/file.ext`(第 X-Y 行) - **不确定性**:[自动化分析无法确定状态的原因] - **建议**:[需要人工检查的内容]
阶段 3:合并——汇总批次结果
在所有阶段 2 批次子 Agent 完成后,读取每个 sast/hardcodedsecrets-batch-*.md 文件,并将它们合并为一个 sast/hardcodedsecrets-results.md。由你(编排者)直接执行此操作——无需子 Agent。
合并流程:
- 读取所有
sast/hardcodedsecrets-batch-1.md、sast/hardcodedsecrets-batch-2.md……文件。 - 收集每个批次文件中的所有发现,并合并为一个列表,同时保留原始分类和所有详细字段。
- 汇总所有批次的总数,用于执行摘要。
- 按以下格式将合并后的报告写入
sast/hardcodedsecrets-results.md:
# Hardcoded Secrets Analysis Results: [Project Name]
## Executive Summary
- Candidates analyzed: [total across all batches]
- Vulnerable: [N]
- Likely Vulnerable: [N]
- Not Vulnerable: [N]
- Needs Manual Review: [N]
## Findings
[All findings from all batches, grouped by classification:
VULNERABLE first, then LIKELY VULNERABLE, then NEEDS MANUAL REVIEW, then NOT VULNERABLE.
Preserve every field from the batch results exactly as written.]
- 写入
sast/hardcodedsecrets-results.md后,删除所有中间批次文件(sast/hardcodedsecrets-batch-*.md)。
重要提醒
- 读取
sast/architecture.md,并将其内容作为上下文传递给所有子 Agent。 - 阶段 2 必须在阶段 1 完成后运行——它依赖侦察结果。
- 阶段 3 必须在所有阶段 2 批次完成后运行——它依赖所有批次的输出。
- 每个子 Agent 处理 3 个候选项。如果候选项总数为 1-3 个,则使用单个子 Agent。如果有 10 个,则使用 4 个子 Agent(3+3+3+1)。
- 并行启动所有批次子 Agent——不要按顺序运行。
- 每个批次子 Agent 只接收侦察文件中分配给它的候选项文本,而不是整个侦察文件。这样可以让每个子 Agent 的上下文保持精简、聚焦。
- 关键区别在于是否可公开访问:Django 视图中硬编码的 AWS 密钥是不良实践,但对于此技能来说并不构成发现(它位于服务端)。同一个密钥如果出现在 React 组件中,则构成发现,因为它会随代码发送到浏览器。
- 不确定时,追踪导入链:
src/utils/config.ts中的文件可能同时被服务端和客户端代码导入。检查它被哪些代码导入。如果任何客户端代码路径导入了它,密钥就会暴露。 - 移动应用始终属于公开内容:Android、iOS、React Native、Flutter 和 Xamarin 应用中的所有源代码都应视为可提取。APK 可以用
apktool/jadx反编译,IPA 可以检查,React Native 中的 JS bundle 是明文。 - Firebase 客户端配置通常不是密钥:标准 Firebase 客户端配置(
apiKey、authDomain、projectId等)是为客户端使用而设计的,并由 Firebase 安全规则保护。仅标记 Firebase 管理员/服务账号密钥或服务器密钥(例如FIREBASE_ADMIN_SDK,或包含private_key的服务账号 JSON)。 - Stripe 可发布密钥不是密钥:
pk_live_*和pk_test_*是为客户端使用而设计的。仅标记sk_live_*和sk_test_*(秘密密钥)。 NEXT_PUBLIC_*、REACT_APP_*、VITE_*环境变量:这些变量会在构建时嵌入客户端 bundle。如果代码引用process.env.NEXT_PUBLIC_API_KEY,则该值可由客户端访问——但实际硬编码值通常位于.env文件中,该文件通常会被 gitignore 忽略。只有在源代码中硬编码了实际密钥值时才标记;仅从环境变量读取时不要标记。- 在输出中遮盖密钥:展示代码片段时,始终对密钥值进行部分遮盖(例如
AKIA****WXYZ、sk_live_****abcd)。切勿在结果文件中写入完整密钥值。 - 对公开可访问性存疑时,将其分类为“需要人工审查”,而不是“无漏洞”。在安全评估中,漏报比误报更糟。
- 清理中间文件:写入最终的
sast/hardcodedsecrets-results.md后,删除sast/hardcodedsecrets-recon.md和所有sast/hardcodedsecrets-batch-*.md文件。