一键导入
secret-detection
硬编码凭据 / 密钥白盒扫描——系统识别仓库 / 配置 / CI / git 历史里的密码、API Key、OAuth Secret、JWT Secret、数据库连接串、私钥、Cookie 加密 Key、IV、Cloud Access Key 等敏感字面量。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
硬编码凭据 / 密钥白盒扫描——系统识别仓库 / 配置 / CI / git 历史里的密码、API Key、OAuth Secret、JWT Secret、数据库连接串、私钥、Cookie 加密 Key、IV、Cloud Access Key 等敏感字面量。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
| name | secret-detection |
| description | 硬编码凭据 / 密钥白盒扫描——系统识别仓库 / 配置 / CI / git 历史里的密码、API Key、OAuth Secret、JWT Secret、数据库连接串、私钥、Cookie 加密 Key、IV、Cloud Access Key 等敏感字面量。 |
| when-to-use | 当需要检查代码中是否存在硬编码的密钥、API Key、密码等敏感信息时 |
| allowed-tools | bash,read_file,list_files,rg |
| user-invocable | true |
| argument-hint | [target_path] |
| arguments | ["target_path"] |
按"代码 pattern + 配置介质 + 文件格式"三维识别本能力命中场景(不按业务命名)。
代码 pattern 维度(grep 命中字面量赋值):
password\s*[:=] / passwd\s*[:=] / pwd\s*[:=] / secret\s*[:=] / token\s*[:=] / apikey\s*[:=] / api_key\s*[:=] / access[_-]?key / client[_-]?secret / private[_-]?keyprivate static final String PASSWORD = "..." / @Value 默认值含明文const KEY = '...' / const TOKEN = "..." / template literal 拼接凭据SECRET = '...' / settings.py 顶层赋值const SECRET = "..." / var apiKey = "..."export TOKEN=xxx / API_KEY=xxx 写死配置介质维度(按文件结构识别——只看代码会漏配置):
.env / .env.local / .env.production / .envrcsrc/main/resources/application*.yml / application*.properties / bootstrap.yml / web.xmlconfig/*.json / package.json scripts 段含凭据settings.py / local_settings.py / config.pyconfig/*.yaml / cmd/*/main.go 默认值config.yaml / secrets.json / *.toml / *.iniDockerfile ENV / ARG / docker-compose*.yml / k8s/*-secret.yaml.github/workflows/*.yml / .gitlab-ci.yml / Jenkinsfile / azure-pipelines.yml**/fixtures/ / **/testdata/(即使是测试也可能误入生产构建)文件格式维度(私钥 / 证书签名):
*.pem / *.key / *.p12 / *.pfx / *.jks / *.crt-----BEGIN (RSA |EC |DSA |OPENSSH |ENCRYPTED |)PRIVATE KEY-----反向信号(不命中本能力):
debug=true / allow-all-origins)→ 走 dangerous-config凭据明文存在于仓库、构建制品、日志或错误返回,意味着任何能读取该资源的人(开发者、CI runner、镜像下载者、日志聚合系统)都能取得这把钥匙。一旦凭据落入未受信范围,攻击者可凭其调用上游 API、登入数据库、解码 JWT、解密历史数据,进而横向移动 / 接口滥用 / 数据泄露。
git 仓库的特殊放大效应:一次提交永久残留 git 历史——即使后续 commit 删除明文,旧 commit 仍可被 git log -p --all 取回。轮换(rotate)只能让旧 key 失效,无法让已泄露的 key 消失;若上游服务签发的 token 不可主动吊销(如某些长期 API Key),影响周期等于服务可用周期。
本能力以字面量扫描为核心,不做跨函数追踪(跨函数 source 到加密 sink 的可达性追踪交 dataflow-analysis)。
代码层 source 集合(白盒视角下的"凭据字面量"):
AKIA[0-9A-Z]{16}ghp_[A-Za-z0-9]{36} / gho_ / ghu_ / ghs_sk_(test|live)_[A-Za-z0-9]{24,} / pk_(test|live)_xox[abprs]-[A-Za-z0-9-]+AIza[0-9A-Za-z_-]{35}[a-zA-Z0-9+/]{86}==eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+-----BEGIN .*PRIVATE KEY-----password|passwd|pwd|secret|token|apikey|api[_-]?key|access[_-]?key|client[_-]?secret 后接非占位符字符串代码层 sink 集合(凭据被消费 / 落库的位置——本能力主要做"sink 位置就地标注",不追跨函数):
http.Header.Set("Authorization", ...) / axios.create({headers})aws.NewSession(credentials.NewStaticCredentials(...)) / stripe.Client(secret)AES.new(key, ...) / cipher.Init(key) / IV 字面量mysql://user:pass@host / Database.connect(dsn)数据流追踪规则:
SECRET = "..." 定义在一处、消费在另一处)只追同包 / 同模块内的引用,确认是否真被加密 / 鉴权 sink 消费本能力覆盖的密钥 / 凭据主流变体(按已知主流覆盖,不追求穷举):
| 类型 | 静态识别特征 | 白盒识别难点 |
|---|---|---|
| 硬编码密码 | 字段名 `password | passwd |
| API Key | 字段名 `api[_-]?key | apikey + 长字符串;含服务前缀(AKIA/sk_`) |
| OAuth Client Secret | client_secret / clientSecret 字段 | 测试 client_secret 与生产难区分 |
| JWT Secret(签名密钥) | jwt.sign(payload, "<secret>") / setSigningKey | 弱 secret(secret / 123456)字符串短,被字段名约束识别 |
| 数据库连接串明文 | mysql|postgres|mongodb|redis://user:pass@host | password 段可能 URL 编码 |
| 私钥文件落库 | 头标记 -----BEGIN .*PRIVATE KEY----- / 扩展名 .pem/.key/.p12/.pfx | 无头标记的裸 base64 段易漏 |
| Cookie 加密 Key / Session Secret | SECRET_KEY / cookie_secret / session_key 字段 | Django / Flask 默认占位符常被遗留 |
| 加密 IV 硬编码 | iv = "1234567890ABCDEF" / 16/12 字节字面量 | IV 看似无害,但固定 IV 让 AES-CBC / GCM 失效(密钥重用) |
| 测试凭据混入生产 | 真凭据出现在 test/ / fixtures/ 但被生产 build 引用 | 需追构建 include / exclude 规则 |
| Webhook Secret | webhook_secret / WEBHOOK_TOKEN / Stripe whsec_ / GitHub X-Hub-Signature 密钥 | 通常短字符串无特征前缀 |
| Cloud Access Key(AWS / Azure / GCP) | 各平台前缀 + 配套 secret access key 紧邻出现 | secret access key 无前缀,需靠"Access Key 附近"上下文识别 |
按项目结构构建"扫描面"——能否命中真凭据取决于扫描面是否覆盖配置 / CI / 私钥介质,只看源码扩展名会漏 .env / .yml / .pem。
下列框架 / 项目类型仅作类似项目示例 不限于此;以目标实际栈为准。
.env / .env.local / .env.development / .env.production / .env.test / .envrc.env.example(应只含占位符——若含真凭据是误入)secrets/ 子目录.git/(若项目含 git 历史扫描需求)src/main/resources/application*.{yml,yaml,properties} / bootstrap.yml(Config Server 客户端)WEB-INF/web.xml / pom.xml settings server 段src/main/resources/*.jks / *.p12(keystore)src/test/resources/ —— 测试 fixture(可能误入生产构建)settings.py / local_settings.py / config.py / secrets.py*/settings/*.py(按环境拆分)/ instance/config.py(Flask)pyproject.toml / setup.cfg / .env*package.json scripts 段(CI 步骤写死的密钥)config/*.json / config/default.json(node-config).npmrc(含 npm token)/ src/config/*.ts / .env*config/*.yaml / config/*.tomlcmd/*/main.go 默认值 / internal/config/*.go 常量定义Dockerfile:ENV KEY=... / ARG SECRET=...docker-compose*.yml:environment: 段明文凭据k8s/*.yaml / helm/values.yaml:Secret 资源 base64 明文(即使是 kind: Secret 资源也可能错放进仓库——base64 ≠ 加密).github/workflows/*.yml:env: 段硬编码而非 ${{ secrets.X }}.gitlab-ci.yml:variables: 段Jenkinsfile:environment {} 段azure-pipelines.yml / bitbucket-pipelines.yml.circleci/config.ymlscripts/*.sh / *.ps1 / Makefileexport TOKEN=xxx / KEY=xxx 直接赋值.git/ 全量克隆后用 git log -p --all -S "<候选片段>"--since=<date> 或 -n <N> 控制扫描成本同目录下的配置文件可能同时触发两个能力——凭据 / 密码 / 密钥归本能力;调试模式 / 默认危险值 / 弱 TLS / 过宽 CORS 归 dangerous-config。同一行配置可能命中两个能力(如 debug=true + admin_password=admin),各自独立成行。
下表列主流框架的"安全形态 vs 危险形态"对照——帮助识别"看似在用 Vault / KMS 但代码里残留默认明文"这类常见漏点。
| 框架 / 平台 | 安全形态 | 危险形态 |
|---|---|---|
| Spring Boot | @Value("${db.password}") + 外部 Vault / Config Server | private static final String PASSWORD = "..." / application.yml 明文 |
| Spring Cloud Vault | spring.cloud.vault.token 由 K8s ServiceAccount 注入 | bootstrap.yml 写死 root token |
| Node.js | process.env.API_KEY + dotenv-vault / AWS SM SDK | const KEY = '...' / package.json scripts 内联凭据 |
| Python / Django | os.environ['SECRET'] + django-environ + KMS | SECRET_KEY = '...'(settings.py 顶层) |
| Python / Flask | app.config.from_envvar('CONFIG') + Vault | app.config['SECRET_KEY'] = '...' |
| Go | os.Getenv("API_KEY") + Vault SDK / AWS SM | const SECRET = "..." / var apiKey = "..." |
| HashiCorp Vault 集成 | vault.Read("secret/data/<path>") 运行时拉取 | 配置里写 vault_root_token = "..." |
| AWS Secrets Manager | secretsmanager.GetSecretValue 运行时拉取 | 配置文件硬编码 aws_access_key_id / aws_secret_access_key |
| Azure Key Vault | SecretClient + DefaultAzureCredential(Managed Identity) | connection_string = "..." 写死 storage key |
| K8s | valueFrom: secretKeyRef: | value: "明文凭据" |
| CI / GitHub Actions | ${{ secrets.X }} 引用 | env: KEY: "明文" |
| CI / GitLab | masked / file-type CI variable | variables: KEY: "明文" |
通用安全反模式(任何栈都适用):
.env 里仍残留默认明文兜底"——开发者改测试环境时遗留.gitignore 漏写"加载本 skill 时按这些问题思考(按"凭据语义"而非业务命名):
xxx / your- / replace-me / <placeholder> / example / changeme / dummyos.getenv("KEY") or "DEFAULT_SECRET"localhost / 内网服务的凭据风险低于指向公网 SaaS 的凭据本能力是字面量扫描为主、轻度跨文件回溯为辅,不做跨函数链路追踪——跨函数追踪走 dataflow-analysis,规则化高频 sink 命中走 sast-scan
secret桶。
.env* / CI / 私钥介质 / Shell 脚本 / git 历史# 字段名 + 字面量赋值(覆盖多种引号风格)
rg -i --pcre2 '(password|passwd|pwd|secret|token|apikey|api[_-]?key|access[_-]?key|client[_-]?secret|private[_-]?key)\s*[:=]\s*["\x27`][^"\x27`]{4,}["\x27`]'
# 配置文件中 YAML / properties 风格
rg -i '(password|secret|token|apikey|api[_-]?key):\s*\S+' --type yaml
rg -i '(password|secret|token|apikey)\s*=\s*\S+' --type properties
# 私钥文件签名
rg -- '-----BEGIN (RSA |EC |DSA |OPENSSH |ENCRYPTED )?PRIVATE KEY-----'
# 私钥文件落库(按扩展名 + 内容核验)
list_files **/*.{pem,key,p12,pfx,jks,crt}
# AWS Access Key
rg 'AKIA[0-9A-Z]{16}'
# GitHub Token
rg 'gh[oprsu]_[A-Za-z0-9]{36,}'
# Stripe
rg 'sk_(test|live)_[A-Za-z0-9]{24,}'
# Slack
rg 'xox[abprs]-[A-Za-z0-9-]+'
# GCP API Key
rg 'AIza[0-9A-Za-z_-]{35}'
# JWT
rg 'eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+'
+/=_-)的字符串重点核验detect-secrets / trufflehog filesystem <path> --json / gitleaks detect --source <path>(若环境可用)# 限定深度(避免大仓库扫描爆炸)
git log -p --all --since="1 year ago" -S "<候选密钥片段>"
# 工具加速
gitleaks detect --source . --log-opts="--all --since=2024-01-01"
扫描深度(commit 数 / 时间窗口)必须显式标注在产物里——受限范围不等于"该子系统无历史泄露"。
排除以下模式(FP 高发):
xxx / your- / replace-me / <placeholder> / example / changeme / dummy / foobar / test1231234567 / password123——除非字段名暗示是默认密码)aaaaaaaa / 00000000)test/ / tests/ / __tests__/ / spec/ / fixtures/ / testdata/ / mock/ 的命中:仍要标注,但严重度可降webpack.config.js / pom.xml <resources> / Go embed)把测试资源打进生产构建——按生产凭据处理以下是已知的检查角度,作为基线起点而非必检硬清单。结合目标代码动态调整,按三态标注(
[x]/[-]/[+])处置。
secrets.X 引用的已列env: 明文与 base64 Secret 资源已识别闭环判定 / 取证完整性 / 破坏性动作以 common/closure-verification.md 为准,下面只列本能力特有的判定上限与产物契约。
为什么这里是「必须」:本节属交付契约——产物结构关系到下游 dataflow-analysis /
result-with-file机器消费;明文凭据若误写入产物会让产物自身成为二次泄露源,因此产物契约是刚性要求。
本能力作为白盒原子能力,判定上限为 static-confirmed,不等于动态 confirmed。
| 静态状态 | 判据 | 升级路径 |
|---|---|---|
static-confirmed(落 status=needs_review) | 字面量在仓库内 + 不是占位符 / 不是测试 mock + 特征匹配真实凭据格式(前缀 / 长度 / 熵) | 验证凭据真实可用(一般不主动验证——避免触发供应商风控);改为推 owner rotate 后观测;rotate 成功证明凭据真实有效 → confirmed |
static-unknown(落 status=needs_review + 标注 unknown) | encrypt-at-rest 凭据(.env.encrypted / .sops.yaml)/ 远程 Vault 引用 / 仅在 CI 注入的 secret 命名变量 / 高熵长串但无任何字段名 / 上下文线索 | 需读取实际配置 / 提取构建期注入逻辑,或推 owner 确认 |
not_vulnerable(落 status=not_vulnerable) | 已确认占位符 / 已确认测试 fixture 且不进生产构建 / 已迁移到环境变量且配置文件只剩引用(如 ${ENV_VAR}) | 不适用 |
禁止白盒独立判 confirmed——无可观测效果证据(成功调用、成功登录、rotate 反馈)仅静态命中不构成"真凭据真生效"。
为什么这里是「必须」:产物结构是下游机器消费的接口,聚合 / 省略 / 区间会让 result-with-file 计数闸门失效;而明文密钥本身是高敏数据,产物若包含真凭据明文会让 jsonl 自身成为二次泄露源——本能力比其他白盒能力多一条密钥脱敏强约束。
每确认一条候选立即 append 一行到 shared/coverage-ledger/findings/secret-detection.jsonl,不等汇总阶段回头整理(why:"事后总结"是聚合 / 区间 / "等"省略的根源):
{
"id": "secret-001",
"title": "硬编码 AWS Access Key",
"severity": "high",
"cwe": "CWE-798",
"source": "AWS_ACCESS_KEY",
"sink": "config/aws.yaml:12",
"entry_point": "systemic",
"status": "needs_review",
"confidence": "static-confirmed",
"file_location": "config/aws.yaml:12",
"source_report": "secret-detection",
"description": "AKIA**** 前缀匹配 AWS Access Key 格式;该文件随仓库分发"
}
字段约束:
id 带 secret- 前缀全局唯一status ∈ confirmed | needs_review | not_vulnerable | false_positive | superseded(白盒默认 needs_review)confidence ∈ static-confirmed | static-unknown(与本节判定上限对齐)(file, line, secret_type) 三元组任一不同即各自独立成行——禁止合并折叠(如"5 个 API Key 在同一文件"必须落 5 行)entry_point 填 systemic;source 填密钥类型,sink 填泄露位置(file:line)file_location 填 file:line,不留空、不写区间特殊产物契约(密钥脱敏,必须遵守):
AKIA**** / ghp_**** / sk_test_**** / -----BEGIN PRIVATE KEY-----...****description 字段只写"前 N 字符 + 类型 + 上下文线索",不写完整 base64 / 完整 token禁止:
why:白盒"已无敏感信息"结论是覆盖完整性产物声明,缺失反向验证会让下游误信"该仓库无凭据泄露"。
写"未发现硬编码凭据"或"已完整审计"前,产物必须包含:
static-unknown 单元格的具体原因(加密 at-rest / Vault 引用 / 高熵无上下文)清单不完整 → 结论降级为 partial-coverage。
反例 1:测试 fixture 里的占位符 token
fixtures/ / testdata/ + 字符串明显是凑数(test-api-key-1234 / dummy-secret)→ 非真凭据tests/fixtures/auth_response.json 含 "token": "test-api-key-1234"test / dummy / fake / mock 关键字;上下文是 mock 响应数据false_positive;但若构建规则把 fixtures/ 打进生产产物则仍要标注反例 2:文档示例代码片段
README.md 含 export AWS_ACCESS_KEY=AKIAIOSFODNN7EXAMPLE(AWS 官方示例 key).md / *.rst / docs/;key 是已知公开示例值(AKIAIOSFODNN7EXAMPLE 是 AWS 文档广为使用的示例)false_positive反例 3:OpenAPI / Swagger 文档展示用 key
openapi.yaml 含 example: "Bearer eyJhbGc..." 是 spec 自带的展示example: / default: 段;JWT payload 解码后字段无业务含义"sub": "string" 等占位则归 FP反例 4:base64 编码的凭据(特征前缀消失)
AKIA 等前缀特征,单纯特征前缀扫描漏报config.yaml 含 key: QUtJQVlPV1lYV1lPUVVZWVdYVlk=(base64 编码的 AWS key)key / secret)+ 字符串是 base64 形态(仅 [A-Za-z0-9+/=])+ 长度匹配解码后凭据长度反例 5:多段拼接构造的凭据
const KEY = 'AKIA' + 'IOSFOD' + 'NN7EXAMPLE'反例 6:自定义混淆但运行时可复原
var key = decode(rot13("...")) / xor(constBytes, magicByte)decode / decrypt / obfuscate)+ 常量字节数组传入反例 7:私钥未带头尾标记仅纯 base64 段落
.env 含 RSA_PRIVATE_KEY="MIIEvQIBADANBgkq..."(无 -----BEGIN)private_key / rsa_key / ssh_key)+ base64 长度匹配 RSA 私钥(通常 > 1600 字符)反例 8:YAML / TOML 字符串折叠形态
>- / |- 折叠让多行字符串看似不像凭据secret: >-\n AKIA\n IOSF...password|secret|key 字段反例 9:环境变量引用 vs 默认明文
${VAR} 引用是安全的,但 ${VAR:-默认明文} 兜底等同明文docker-compose.yml 含 KEY: "${API_KEY:-sk_live_realsecret123}"${...:-...} / ${...:?...} 兜底语法 + 兜底值是真凭据static-confirmed白盒底线:不假装看到看不到的代码。本能力的可观测能力到字面量 + 字段名匹配为止。
下面这些情形本能力无法继续追踪,必须落 static-unknown 并显式标注原因,不允许默认为 not_vulnerable:
secretRef: / valueFrom: / vault.read(...) / secretsmanager.get(...)。代码只看到引用名,不见明文。处置:标 n/a(不在白盒可见范围);若需确认 Vault 内容则推 owner / 走运维侧。os.environ['X'] / process.env.X,凭据由 K8s ServiceAccount / 进程启动脚本注入。处置:标 not_applicable(不是漏洞——这是正确做法);但若发现 .env 文件随仓库分发则就此回归本能力。DefinePlugin / Vite import.meta.env / Spring @Value 绑定外部源。处置:需读构建配置确认注入源;构建配置不可见则标 static-unknown。.env.encrypted / .sops.yaml / ansible-vault 文件。处置:标 static-unknown,记录加密形态;解密需密钥不在审计范围。git log -p --all 可能 OOM / 超时。处置:显式标注"扫描深度 N 个 commit / 时间窗口 X 月",未扫深度按 partial-coverage 处理。unknown 推 dependency-decompile;不能直接 not_vulnerable。uuid.v4() 生成的 session secret 写入运行时缓存。处置:本能力不追运行时——若静态代码里看到生成逻辑无明文落库,标 not_applicable。底线:本能力写"该仓库无硬编码凭据"前,所有 static-unknown 单元格必须显式列出原因。否则结论降级为 partial-coverage。
id-token / GitLab JWT / AWS AssumeRoleWithWebIdentityvalueFrom: secretKeyRef: + External Secrets Operator 同步 Vault.env.example 留占位符;真 .env / *.pem / *.key / *.p12 / *.pfx / *.jks / secrets/ 全部加入 .gitignoregit filter-branch / BFG Repo-Cleaner 把历史中的明文擦除;推送 force-push 后通知所有 fork / clone 重新同步MaskingConverter / Winston format.uncolorize).env 路径)白盒建模——一次深度建模产出五张共享模型:项目架构(技术栈/分层/框架自有封装/闭源依赖位置)、 入口点(路由/中间件信任边界)、认证与权限(会话/角色/多租户/归属字段)、业务(实体/流程状态机/ 业务不变量/高价值资产)、全局威胁(攻击面×漏洞类别的适用性映射,供下游逐一全测)。本能力不做漏洞判定,为后续 漏洞维度分析建立共享底图。
OS 命令注入综合检测——覆盖直接命令拼接 / shell 元字符 / 参数注入 / 间接 RCE,按回显 / 时间 / 带外通道分诊。 流量中参数值含主机名 / URL / 文件名 / 命令片段、响应里出现 shell 错误关键字(`/bin/sh` / `cmd.exe` / `command not found`)、注入 `sleep N` 耗时增加、上传后异步处理链路时使用。
文件上传多策略综合检测——覆盖扩展名 / MIME / 魔术数 / 解析漏洞 / 上传链组合(LFI / Zip Slip / SVG XSS / SVG XXE)。 流量含 multipart/form-data 上传、响应回显落盘路径、上传后文件可被 GET 解析、上传字段含 filename / path 可控时使用。
IDOR 水平越权检测 — 通过替换资源标识符(ID/UUID/路径)访问他人资源的风险;适用于用户资料、订单、文档、租户隔离场景。
检测路径穿越和本地文件包含(LFI)风险;当目标存在文件读取/下载/预览功能且含路径参数时触发;适用于文件下载、日志查看、模板加载等场景。
黑盒建模 — 迭代式攻击面建模,按站点级 / 页面级 / 功能级三粒度推进;进入新页面即触发一次页面级建模、切换新身份各刷新一次,产出端点账本与页面语义模型,为后续漏洞维度的适用性判断提供依据。