跨语言、跨项目的安全底线:威胁建模何时做、密钥怎么管、依赖和制品怎么防投毒、常见 Web 漏洞的通用防法、调用大模型时的提示注入与数据出网,以及每类安全工具默认用哪个。
新增对外入口、跨信任边界、处理不可信文件或 URL、新增有副作用的模型工具、处理敏感数据之前,先在仓库里写一份轻量威胁模型
怎么检查:PR 模板加「是否触及上述情况」勾选项;勾选时评审者检查威胁模型文件是否新增或更新
为什么、来源
为什么:设计阶段发现的问题修起来最便宜;按触发条件做,避免每个小改动都走重流程。
最小内容:资产(密钥、客户数据、发布能力等)、数据流和信任边界、主要威胁(可按 STRIDE 逐项过)、缓解措施、对应测试、负责人。
用 Markdown 加 Mermaid 数据流图放在仓库里即可,随代码一起评审;隐私威胁(LINDDUN)交 27。
风险的接受由人决定,Agent 可以起草,但不能批准自己找出的风险。
以 OWASP ASVS 作为可验证的安全需求来源;Top 10 类清单只做覆盖检查,不当验收标准
怎么检查:安全评审时检查需求或测试是否引用 ASVS 条目编号,而不是只写「符合 Top 10」
为什么、来源
为什么:Top 10 是风险排名,没有可逐条验证的要求;ASVS 每条都能写成测试。
每条安全例外(抑制规则、忽略漏洞、放宽门禁)必须写明负责人、原因、补偿措施和到期日;不允许永久抑制
怎么检查:CI 校验例外文件(如 .gitleaksignore、osv-scanner.toml 的忽略项、.trivyignore)每条都有到期日和理由,过期即失败
为什么、来源
为什么:没有到期日的例外会永久沉积成看不见的风险。
安全检查失败不得被吞掉:安全任务禁止用 || true、continue-on-error 之类放行;扫描出错或漏洞库过期时结果记为「不确定」,不记为通过
怎么检查:用脚本或 Actions 静态检查查找安全任务里的 || true、continue-on-error: true;扫描器非零退出码必须让任务失败
为什么、来源
为什么:静默失败的扫描比没有扫描更危险,因为大家以为已经查过了。
对外发布或交付的仓库必须有 SECURITY.md,写明私密报告渠道和支持的版本;未修复的漏洞不在公开 issue、提交信息或 PR 描述里披露细节
怎么检查:CI 检查 SECURITY.md 存在且含联系方式;开启代码托管平台的私密漏洞报告功能
为什么、来源
为什么:没有私密渠道,报告者只能公开提 issue,等于把漏洞公之于众。
私有化交付的项目要提供不依赖公网平台的报告渠道(客户侧联系人或交付工单)。示例邮箱上线前必须换成真实且有人值守的地址。
订阅所用语言生态、框架、基础镜像和安全工具自身的安全公告,并开启自动依赖安全更新
怎么检查:仓库开启 Dependabot 或 Renovate 的安全更新;关键组件的公告列表记录在仓库文档里
为什么、来源
为什么:不订阅就只能等扫描器下一次运行才发现,或者干脆不知道。
漏洞按「是否已被利用、严重度、是否可达、暴露面」分流并给出修复期限;不只看 CVSS 分数
怎么检查:漏洞工单记录分流依据和期限;定期报表列出超期项
参考值:参考值(组织策略,非标准强制):已被利用(列入 CISA KEV)且对外暴露的,立即遏制、两周内修复(参照 CISA BOD 22-01 对联邦机构的默认期限;该指令已被新指令取代,见待确认);严重 30 天内;高 60 天内;中 90 天内;低随例行更新。
理由:KEV 代表真实攻击;其余档位是常见的行业做法,按自身发布节奏调整并写进安全策略。
为什么、来源
为什么:只看分数会把精力浪费在不可达的高分漏洞上,同时漏掉正在被利用的中等漏洞。
主动 DAST 扫描和渗透测试只对明确授权的测试环境运行,固定目标清单和速率
怎么检查:扫描任务配置目标白名单并只在标记为测试的环境运行;评审时核对授权记录
为什么、来源
为什么:主动扫描会写数据、发请求,打到生产或第三方资产会造成真实损害和法律风险。
真实密钥、令牌、密码不得出现在源码(含 Git 历史)、配置文件、镜像层、构建产物、日志、测试快照和提示词里
怎么检查:提交前钩子和 PR 跑密钥扫描(增量);主分支定期扫全部历史;发布前扫镜像和制品
为什么、来源
为什么:进过仓库或镜像的密钥会被复制到无数地方,几乎不可能收回。
.gitignore 不是防护:已提交的历史、CI 日志和缓存里仍可能有。测试用的假密钥要明显是假的(如带 EXAMPLE 字样),并在扫描配置里按路径白名单放行。
扫描器的「联网验证密钥是否有效」功能会主动连接外部服务,默认关闭,需要时单独批准;断网环境禁止开启。
密钥不通过命令行参数传递,改用环境变量注入、权限 0600 的临时文件、标准输入或密钥管理系统
怎么检查:评审时检查脚本和 CI 配置里是否把密钥拼进命令行(如 --password=、-p<值>);密钥扫描规则覆盖 CI 配置文件
为什么、来源
为什么:命令行参数会被同机其他用户的进程列表看到,也会进 shell 历史和 CI 日志。
运行时密钥由密钥管理系统或部署平台注入,不打包进镜像,不写进明文配置文件;必须随仓库版本化的少量配置用 SOPS 加密
怎么检查:镜像扫描检查层内是否含密钥;评审时检查配置文件里没有明文密钥
为什么、来源
为什么:镜像和配置文件会被分发、缓存、备份,里面的密钥等于公开。
加密用的私钥和密文不要放在同一个制品或同一个仓库里。
每个凭证登记负责人、用途、权限范围、到期时间和撤销方法;优先使用短期按需签发的凭证
怎么检查:凭证清单文件按 schema 校验;定期列出无负责人或已过期的条目
为什么、来源
为什么:出事时找不到负责人、不知道怎么撤销,遏制就会拖延。
与生产相关的静态凭证要有演练过的轮换流程:签发新凭证、新旧并行、切换、撤销旧凭证、确认旧凭证失效
怎么检查:演练记录里有「旧凭证调用失败」的证据
为什么、来源
为什么:没演练过的轮换在真正泄漏时常常因为漏改某个服务而回退。
没有通用的「每 N 天轮换」规则;按影响面、泄漏风险和服务商要求定周期,但必须做到泄漏时能立即撤销。
疑似泄漏的密钥立即撤销或轮换,再清理 Git 历史、日志和制品里的副本;改写历史不能代替撤销
怎么检查:泄漏工单必须记录撤销时间和「旧密钥已失效」的验证结果
为什么、来源
为什么:密钥一旦暴露就要假定已被拿走,删掉副本不会让它重新变安全。
正式构建的依赖集合由锁文件和摘要决定;构建和部署不使用未审核的 latest 标签或浮动版本
怎么检查:CI 用锁文件安装(如 npm ci、--frozen-lockfile、--require-hashes),锁文件与清单不一致即失败;镜像引用检查是否带摘要
为什么、来源
为什么:浮动版本会在你不知情时换成新代码,包括被投毒的版本。
CI 里引用的第三方 Action、插件、扫描器和容器镜像必须按完整提交 SHA 或镜像摘要固定,不按可变标签引用
怎么检查:OpenSSF Scorecard 的 Pinned-Dependencies 检查,或用脚本检查工作流里 uses: 是否都是 40 位 SHA
为什么、来源
为什么:标签可以被改写。2026 年 3 月 trivy-action 和 setup-trivy 的大部分标签被强推成窃取凭证的版本,按标签引用的流水线直接中招。
固定之后由 Dependabot 或 Renovate 提更新 PR,人看过再合并。扫描器下载二进制时同样要校验签名或校验和。
来自外部贡献者或不可信分支的 PR,安装依赖和运行测试时不得拿到长期凭证和生产密钥;CI 令牌默认只读
怎么检查:检查工作流触发器(禁止在 pull_request_target 等有密钥的上下文里检出并运行 PR 代码)和令牌权限设置
为什么、来源
为什么:依赖安装脚本和测试就是任意代码执行;Shai-Hulud 等 npm 攻击就是靠它窃取 CI 和云凭证。
新增依赖时评估来源、维护活跃度、安装脚本、许可证和是否有更轻的替代
怎么检查:CI 在依赖清单变化时提示评审;可参考 OpenSSF Scorecard 分数
为什么、来源
为什么:每个依赖都扩大攻击面;拼写仿冒、账号被盗、无人维护都是真实风险。
依赖的新版本发布后先等一段冷却期再升级,紧急安全修复除外
怎么检查:用包管理器或依赖更新机器人的最小发布时长设置(具体配置见 10–15)
参考值:参考值数天到一周。理由:近年 npm 投毒事件多在几天内被发现处置;太长会拖慢安全修复,所以安全更新例外。
为什么、来源
为什么:多数恶意版本在发布后几天内被发现并下架,冷却期能避开这段窗口。
PR 对变更的依赖跑依赖漏洞扫描,主分支定期全量扫描;存在不可接受漏洞时阻断发布
怎么检查:CI 必过检查运行 OSV-Scanner(或语言专用工具);阻断阈值写在安全策略里,例外走 SEC-003
为什么、来源
为什么:已知漏洞是最容易被批量利用的入口,修复成本也最低。
容器镜像在构建时和镜像仓库里定期扫描,覆盖系统包和语言依赖;基础镜像按摘要固定
怎么检查:CI 对构建出的镜像运行 Trivy,镜像仓库按计划重扫;Dockerfile 检查 FROM 是否带摘要
为什么、来源
为什么:镜像里的系统包会持续爆出新漏洞,构建时干净不代表现在干净。
对外发布或交付给客户的制品必须附带由构建产物生成的 SBOM(CycloneDX 或 SPDX)
怎么检查:发布流水线生成 SBOM 并校验格式,SBOM 与制品一起归档
为什么、来源
为什么:新漏洞公布时,要靠 SBOM 才能快速知道哪些交付物受影响;NIST SSDF 要求为每次发布保存组件来源数据。
SBOM 是清单,不是安全结论,漏洞扫描结果要另存。断网交付时一并带上签名公钥或可信根、校验工具和漏洞库快照日期。
SEC-023硬约束检查:自动对外提供服务的后端私有化或断网部署命令行工具供别人引用的库或 SDK 容器镜像和对外发布的二进制必须签名;部署时按允许的签名身份加摘要验证,不信任标签
怎么检查:发布任务用 Cosign 签名;部署前或准入控制里执行验签,失败即拒绝
为什么、来源
为什么:只比哈希挡不住「连哈希一起被替换」;验签身份才能证明是谁发布的。
签名只证明「谁发布了这个摘要」,不证明代码没有漏洞或上游可信。签名只在受控的发布任务里做,签名凭证不暴露给普通构建任务。
SEC-024软指导检查:半自动供别人引用的库或 SDK命令行工具对外提供服务的后端 按 SLSA Build 轨道逐级生成构建来源证明(provenance),不口头宣称达到某个级别
怎么检查:发布物附带来源证明并在部署时校验;宣称的级别要有对应的构建平台证据
为什么、来源
为什么:来源证明回答「这个制品是从哪份代码、在哪台构建机上做出来的」,是追查供应链事件的依据。
SLSA 当前版本把要求分为 Build 和 Source 两条轨道,不能混成一张证书。先做到构建平台自动生成来源证明,高风险项目再提高级别。
断网或私有化环境的漏洞库要本地镜像并记录库的更新日期;超过约定的陈旧期,扫描结果记为「不确定」
怎么检查:扫描任务读取本地漏洞库的生成时间,超期时任务失败或标为不确定
参考值:参考值一周内。理由:主流漏洞库每天更新,超过一周新公布的高危漏洞基本都会漏掉;按环境能接受的风险调整。
为什么、来源
为什么:过期的漏洞库会让扫描「全部通过」,但新漏洞根本不在库里。
在 PR 上运行 SAST 的高置信度规则并阻断,全量规则定期运行
怎么检查:CI 必过检查运行 Semgrep 社区版引擎和语言专用工具;误报写进带到期日的例外
为什么、来源
为什么:PR 只放快而准的规则,团队才不会想办法绕过;全量规则用来发现存量问题。
数据库查询必须参数化,动态表名和排序字段只能来自白名单映射;系统命令用参数数组调用固定程序,不拼接 shell 字符串
怎么检查:SAST 规则查找字符串拼接 SQL 和 shell=True、exec 拼接等写法;注入单测
为什么、来源
为什么:注入仍是最常见、后果最严重的漏洞类别之一。
参数化解决不了授权问题,参数数组也挡不住危险参数(如 --output=/etc/...),这些还要按参数校验。模型生成的文本同样不能直接拼进 SQL 或命令。
不对不可信数据做可执行对象的反序列化;用 JSON 等纯数据格式,YAML 用安全加载器,禁止 pickle 和按任意类名实例化
怎么检查:SAST 规则查找 pickle.loads、yaml.load(非 safe)、Java 原生反序列化等调用
为什么、来源
为什么:不安全的反序列化通常直接导致远程代码执行。
服务端按用户或模型给的 URL 发请求时,限定协议,解析域名后校验目标 IP(拒绝回环、内网、链路本地、云元数据地址),每次重定向都重新校验,并走受限的出口
怎么检查:测试集覆盖内网地址、IPv6、十进制 IP、重定向到内网、DNS 重绑定等用例;评审时检查是否只用正则校验 URL
为什么、来源
为什么:SSRF 能让攻击者借服务器访问内网和云元数据,拿到云凭证;只用正则校验 URL 挡不住。
输出到页面时按上下文编码,不渲染未清洗的 HTML 或 Markdown 原始 HTML;必须渲染富文本时用成熟的清洗库,并配置内容安全策略(CSP)作为纵深防御
怎么检查:lint 或 SAST 规则查找 dangerouslySetInnerHTML、v-html、innerHTML 等用法;检查响应头里有 CSP
为什么、来源
为什么:XSS 能在用户浏览器里冒充用户做任何事;框架默认转义只覆盖文本插值。
CSP 不替代输出编码。脚本策略用 nonce 或 hash,不用 unsafe-inline;新策略先用 report-only 观察再强制。具体写法和清洗库选型见 07。
用 Cookie 维持会话的应用,会修改状态的接口必须有 CSRF 防护(框架自带的令牌或校验 Origin),不能只靠 SameSite
怎么检查:浏览器负例测试从第三方页面发起修改请求,确认被拒绝
为什么、来源
为什么:浏览器会自动带上 Cookie,跨站页面就能冒用用户身份;SameSite 在部分场景和旧浏览器上不生效。
登录后跳转等重定向只允许相对路径或白名单内的域名
怎么检查:测试用 //evil.example、https://evil.example、编码后的协议、user@host 等输入,确认被拒绝
为什么、来源
为什么:开放重定向常被用来做钓鱼和偷 OAuth 授权码。
上传入口必须鉴权,限制大小和数量,按文件内容识别类型(不信扩展名和 Content-Type),用生成的名字存到网站根目录之外,下载时以附件方式返回
怎么检查:测试集覆盖超大文件、伪造扩展名、路径穿越文件名、可执行内容;评审检查存储路径和下载响应头
为什么、来源
为什么:上传是把外部文件放进系统的入口,直接用原文件名或放在可执行目录里会导致覆盖文件和代码执行。
有条件时用独立域名提供用户文件、对文件做病毒扫描。上传和解析进程不共享高权限凭证。文件解析、压缩炸弹和解析器隔离见 20。
生产环境关闭调试模式和目录浏览,CORS 只放行明确的来源,设置安全响应头;错误响应不返回堆栈、SQL 和密钥
怎么检查:ZAP 基线扫描检查响应头和错误信息;配置 lint 检查调试开关和 CORS 通配符
为什么、来源
为什么:安全配置错误是 OWASP Top 10:2025 的第二位,调试信息常直接暴露内部结构和凭证。
SEC-035硬约束检查:半自动调用大模型的应用由编码 Agent 参与开发的仓库 进入模型的外部内容(网页、文件、检索结果、工具返回、邮件、其他 Agent 的消息)一律当数据;它们不能改变系统指令、权限或安全策略
怎么检查:回归测试集放入夹带指令的输入,检查模型没有越权调用工具,策略判定没有被改变
为什么、来源
为什么:提示注入是 OWASP LLM Top 10 的第一位,而且无法靠过滤彻底防住,只能让注入成功也造不成越权。
不把安全过滤器或系统提示词当作唯一防线;验证方法是关掉过滤器后策略仍然成立。外部内容写入长期记忆或知识库时要记录来源,并能撤销。
模型输出进入命令、SQL、HTML、URL、文件路径或工具参数之前,按目标类型校验和编码,与处理用户输入一样
怎么检查:SAST 查找模型输出直接流入 exec、SQL 拼接、innerHTML 等危险调用;负例测试
为什么、来源
为什么:模型输出可能被注入操纵,把它当可信输入就把注入变成了代码执行或 XSS。
SEC-037硬约束检查:半自动调用大模型的应用由编码 Agent 参与开发的仓库 有副作用的工具调用由模型之外的代码做授权判定和参数 schema 校验;高风险操作的人工审批绑定具体目标和参数,参数一变审批作废
怎么检查:测试审批后篡改参数、替换目标的用例,确认执行被拒;审批界面显示系统生成的真实差异,而不只是模型的解释
为什么、来源
为什么:模型可能被诱导滥用工具;只看模型写的说明来审批,容易被「漂亮但歪曲」的解释骗过。
发往外部模型服务的数据先分级;密钥不得发送,个人敏感数据和客户数据按策略脱敏或禁止发送;要求断网的环境不调用外部模型,除非事先批准
怎么检查:模型调用统一经过网关,网关按数据级别执行脱敏或拦截并记录发送的数据类别;断网环境用出口策略和 DNS 记录验证
为什么、来源
为什么:发出去的数据就脱离了控制,可能被服务方留存、用于训练或在其日志里泄漏。
网关和服务选型见 24,个人信息和数据出境的合规要求见 27。
SEC-039软指导检查:半自动调用大模型的应用由编码 Agent 参与开发的仓库 把 MCP 服务、Agent 技能、插件、模型权重和提示词模板当作依赖管理:固定版本或摘要,变更要评审
怎么检查:清单文件记录版本和摘要;变更走 PR 评审
为什么、来源
为什么:工具描述和技能可以在运行时被更新或替换,是一条新的供应链。
没有符合条件的规则。
密钥扫描
Betterleaks(提交前钩子 + PR 增量 + 主分支定期全历史) · Betterleaks MIT;Gitleaks MIT;TruffleHog AGPL-3.0
备选:Gitleaks(已有配置和流水线、暂不迁移时。官方 README 已声明功能冻结、只做安全补丁,作者重心转到 Betterleaks;Betterleaks 定位为可直接替换);TruffleHog(需要验证密钥是否仍然有效,或要扫描 Git 之外的多种来源时;作为独立工具在 CI 里运行,许可证 AGPL-3.0,不要嵌入对外分发的产品或对外服务)
不推荐:用 grep 或自写正则代替
依赖漏洞扫描(SCA)
OSV-Scanner(直接读锁文件或 SBOM,覆盖多种语言生态,数据来自 OSV 库) · Apache-2.0
备选:语言专用工具(govulncheck、pip-audit、cargo-deny / cargo-audit、npm audit、OWASP Dependency-Check)(单一语言项目,或需要调用可达性分析(如 govulncheck)时;用法见 10–15);Trivy 或 Grype(同一个流水线还要扫容器镜像和系统包时,可顺带扫依赖)
不推荐:自己写 CVE 匹配器;只按 CVSS 分数决定阻断
容器镜像扫描
Trivy · Trivy Apache-2.0;Grype Apache-2.0
备选:Grype(配合 Syft 生成的 SBOM)(已用 Syft 生成 SBOM、想基于 SBOM 扫描,或需要第二个扫描器交叉核对时)
不推荐:按可变标签引用扫描器的 Action 或镜像
SAST(跨语言)
Semgrep 社区版引擎 + 团队自审的规则集 · 引擎 LGPL-2.1;Semgrep 官方维护的规则使用 Semgrep Rules License v1.0,限内部使用,不能用于竞争产品或作为服务对外提供,要再分发规则时另找规则来源或自写
备选:Opengrep(希望引擎由社区治理、不受单一厂商政策影响时;是 Semgrep 引擎的社区分叉,同为 LGPL-2.1);CodeQL(关键服务需要更深的跨过程数据流分析时;私有仓库的使用授权要先确认)
不推荐:没读规则就直接用云端托管扫描
SBOM
Syft 生成 CycloneDX JSON · Syft Apache-2.0;CycloneDX 规范 Apache-2.0
备选:SPDX 格式(客户或法规指定 SPDX 时);构建工具原生插件(如 CycloneDX 的 Maven / Gradle 插件)(需要更准确的构建期依赖关系时,见 10–15)
不推荐:把 npm list 之类的输出当 SBOM
签名与来源证明
Cosign(Sigstore)签名 + 按 SLSA Build 轨道生成来源证明 · Apache-2.0
备选:Cosign 私钥签名(断网环境用不了无密钥签名和公共透明日志时);代码托管平台自带的制品证明功能(构建完全在该平台上进行时)
不推荐:只发布 SHA256 校验和
密钥管理
部署平台已有的密钥服务(云 KMS / Secrets Manager 等);必须随仓库版本化的配置用 SOPS + age 加密 · SOPS MPL-2.0;age BSD-3-Clause;OpenBao MPL-2.0;Vault BUSL-1.1;Infisical MIT + ee 商业许可
备选:OpenBao(需要动态签发数据库凭证、短期令牌和统一审计,且能运维一个关键服务时);HashiCorp Vault(组织已在用时继续用;新版为 BUSL-1.1,不是开源许可,自建对外服务前先过法务);Infisical(团队需要现成的密钥管理界面时;主体 MIT,ee 目录是商业许可,要确认所需功能不在 ee 里)
不推荐:明文放 Git 再靠 .gitignore;只为藏几个 API Key 部署多节点密钥集群
DAST
ZAP(PR 或预发跑被动 / 基线扫描,主动扫描只打授权测试环境) · Apache-2.0
不推荐:对生产或客户资产跑主动扫描
威胁建模
仓库里的 Markdown 文档 + Mermaid 数据流图 · Threat Dragon Apache-2.0
备选:OWASP Threat Dragon(团队想用图形界面画数据流图并按 STRIDE 标注时)
不推荐:自造建模工具
依赖与仓库安全健康度
OpenSSF Scorecard · Apache-2.0
安全公告与依赖安全更新
Dependabot(托管在 GitHub 的仓库) · Renovate AGPL-3.0
备选:Renovate(自托管代码平台、多平台或需要更细的分组与冷却期配置时;许可证 AGPL-3.0,作为独立工具运行)
✕ 错误做法:有 .gitignore 就认为密钥不会泄漏
✓ 应该:提交前和 PR 跑密钥扫描,真实密钥一律由密钥服务注入
✕ 错误做法:发现密钥泄漏后先改写 Git 历史
✓ 应该:先撤销或轮换,确认旧密钥失效,再清理副本
✕ 错误做法:CI 里用 uses: 某扫描器@v1 这样的可变标签
✓ 应该:按完整提交 SHA 固定,由更新机器人提 PR 升级
✕ 错误做法:外部 PR 在带仓库和云凭证的 runner 上执行 npm install 和测试
✓ 应该:不可信 PR 在无密钥、令牌只读的环境里跑
✕ 错误做法:把扫描「零发现」当作安全
✓ 应该:同时看漏洞库日期、覆盖盲区,并配合负例测试和人工评审
✕ 错误做法:用 URL 正则白名单防 SSRF
✓ 应该:解析后校验 IP、每跳重查、走受限出口
✕ 错误做法:把安全规则写进系统提示词就算防住了注入
✓ 应该:权限、审批和出口控制放在模型之外强制
✕ 错误做法:有了 SBOM 和签名就认为上游可信
✓ 应该:SBOM 是清单、签名只证明发布者,依赖仍需审查和漏洞扫描
✕ 错误做法:所有高 CVSS 一律阻断、中危一律放行
✓ 应该:结合是否被利用、可达性和暴露面分流
✕ 错误做法:安全例外写进忽略文件后再没人管
✓ 应该:每条例外有负责人和到期日,过期自动失败
✕ 错误做法:自己实现加密、签名、SBOM 生成或 CVE 匹配
✓ 应该:用 SOPS、Cosign、Syft、OSV-Scanner 等现成工具