Claude Code 安全技能包:用 AI 审计 AI 生成的代码 1. 为什么我把安全扫描做成了技能包1.1 AI 写代码越快我心里越没底用了一段时间 Claude Code 之后我最大的感受是它是真的能写能在短时间内把一个模块连框架带测试全给你列出来。但问题也随之而来——AI 生成代码的速度远远快于人的审查速度。我这边一个上午没怎么“写代码”项目里多了好几十个文件功能跑通了可里面藏了多少安全隐患我完全没有底。于是我开始思考能不能反过来利用 Claude Code 的阅读能力让它给自己生成的代码做“事后审计”与其让它在生成阶段盲目追求“能跑通”不如给它一套清晰的安全扫描技能让它像甲方请来的安全顾问一样把项目翻个底朝天。带着这个想法我整理了一套安全技能包包含 6 个开箱即用的安全扫描工具每个工具本质都是一段结构化的审查规则Claude Code 只要读到就能立刻执行。这套东西不一定能替代专业 SAST 工具但作为日常开发的“第一道安全网”效果出乎意料地好。1.2 技能包的工作方式让模型临时扮演专职安全审计员这套技能包的核心思路不是装一堆插件而是通过精心设计的提示词把模型从“写代码的助手”切换成“挑刺的安全审计员”。每次运行一个技能Claude Code 都会按照固定的检查顺序遍历项目中的相关文件执行预设的搜索模式然后把风险点按严重等级输出成结构化报告。这种做法的价值在于传统静态扫描工具往往误报率极高而模型具备上下文理解能力能判断某个可疑写法是不是真的被外部输入控制能理解某段代码是不是在测试环境里的 mock 数据。所以同一个调用点在 它眼里可能被归为“低风险忽略”而不是像传统工具那样一律标红。用模型来做安全扫描的体验有点像“请了个懂业务的同事帮你过代码”而不是“拿扫描仪对着代码库狂扫”。1.3 六把扫描“扳手”的完整清单我最终沉淀下来的 6 个技能覆盖了日常 Web 开发和后端服务里最常出问题的几个区域。下面用一个表先看全局后面逐一对齐到提示词层面。技能名称核心检查目标适合扫描的项目类型硬密钥与敏感信息探测密钥、Token、数据库连接串、私钥泄漏暴露任何语言任何项目依赖与供应链风险扫描过期依赖、危险包、锁文件不一致、来源不明包node / python / go 项目注入与命令执行审计SQL 注入、命令拼接、eval、模板注入、反序列化后端 API 服务认证与越权审查登录校验缺失、水平越权、垂直越权、会话漏洞带有用户体系的 Web 服务数据合规与隐私泄露排查PII 字段泄露、日志打印敏感信息、前端暴露内部字段涉及用户数据的项目AI 幻觉代码专项审计审“上一轮 AI 生成的代码”中的伪安全、假依赖、自定义加密一切由 Claude Code 参与生成的项目现在挨个说实现方法和背后的设计逻辑。2. 技能包落地第一步CLAUDE.md 注册与统一调用入口2.1 把公共规则写进 CLAUDE.md让每次会话都带上安全基线技能包要长期用第一步不是写一堆临时提示词而是给 Claude Code 一个稳定的“行为基线”。我把一套公共约定写进了项目根目录的CLAUDE.md包括三部分第一扫描任务的统一输出格式第二通用排除目录清单第三风险分级标准。你不会希望每次说“帮我扫一下密钥”的时候它用的规则集和上次不一样。CLAUDE.md 的作用就是把这些规矩固化下来。即使过了两周项目从 5 个文件长到 500 个文件新的一次扫描依然按同一套纪律执行。下面这行配置我直接用了很久安全审计输出要求 1. 对风险点按严重等级分类依次为严重(Critical)、高危(High)、中危(Medium)、低危(Low)、提示(Info)。 2. 每个风险点必须给出文件路径、行号范围、风险描述、外部输入是否可控、修复建议。 3. 风险点必须有具体代码引用不允许只给出文件名。 4. 对无法确定的问题标记“待人工确认”不要强行判定。 5. 扫描结束后给出 3 条优先级最高的整改建议。2.2 六个技能的统一输出格式约定光有公共规则还不够还得让不同技能之间的输出能互相比较。我给 6 个技能统一了输出口径每次扫描结果都带一个“风险汇总表”这样不管是跑在本地还是接进 CI结果都能直接解析。表格形式长这样风险等级数量已确认待人工确认严重211高危541如果扫描结果没有任何问题要求它给出“未发现问题的确认说明”以及“本次扫描覆盖的文件范围”。这样做的好处是你不会误以为它没干活——覆盖范围写在结果里一眼就能判断是不是只扫了某个目录而漏了别处。2.3 我能直接复制的初始配置如果你也想在项目里快速把这套包立起来我建议先按下面的结构初始化# 目录规划 skills/ secret-scan.md # 硬密钥与敏感信息探测 dependency-scan.md # 依赖与供应链风险扫描 injection-scan.md # 注入与命令执行审计 auth-scan.md # 认证与越权审查 privacy-scan.md # 数据合规与隐私泄露排查 hallucination-scan.md # AI 幻觉代码专项审计每个技能文件里写清三块内容触发词、扫描步骤、输出模板。比如技能一触发词是“跑一次密钥扫描”那么 Claude Code 就会读取secret-scan.md里的规则按照里面定义的优先级目录开始干活。别把 6 个技能揉成一坨塞到一个提示词文件里拆开以后维护成本会低很多哪个技能误报多了单独调整那个文件即可。3. 硬密钥与敏感信息探测技能先查家里有没有“钥匙挂墙”3.1 为什么要单独做这个技能密钥泄漏听起来是老生常谈但是当你让 AI 帮你写接口对接代码时它很可能顺手把配置里的测试地址和测试密钥一起带进代码注释里。我记得有个项目AI 生成的对接示例里直接写了一行api_key sk-测试用密钥-仅本地使用普通人工审查可能觉得“这是测试密钥无所谓”但这条代码如果被推到公共仓库再被爬虫扫到就是一个实实在在的泄露入口。更麻烦的是有时候 AI 会把密钥写进.env.example里再把.env.example当成模板提交结果模板里含有一个真实可用的数据库连接串。3.2 预置的探测规则这个技能的提示词核心就是给模型一份需要搜索的密钥模式和一套排除规则。我把规则分成几种类型方便它在不同项目里直接套用。请对当前项目执行密钥与敏感信息探测按照以下规则 1. 搜索模式 - 云厂商访问密钥如以特定前缀开头的长字符串 - 私钥块-----BEGIN RSA PRIVATE KEY----- / -----BEGIN EC PRIVATE KEY----- - 常见数据库连接串mysql://、postgres://、mongodb://且包含密码字段 - 通用密钥写法api_key、secret、token、password 等赋值语句值不是占位符 - JWT 签名密钥、Webhook 签名密钥 2. 排除目录node_modules、vendor、dist、build、.git、venv、__pycache__ 3. 排除文件*.test.ts、*.test.js、*_test.go、tests/ 目录下的显式 mock 数据 4. 重点关注新近创建的 .env 文件、配置示例文件、README 中的配置段落 5. 输出时给出“密钥类型、可能影响范围、推荐处置方式”执行的时候我会让它先“解释扫描计划”告诉我它准备查哪几类位置。这样一旦有遗漏我能看出是规则的问题还是模型执行的问题。3.3 实测输出与容易误报的三类地方一次真实扫描它给出的结果通常是这种格式严重config/credentials.example.json - 行 23elasticsearch URI 中包含明文密码 - 建议改为环境变量引用并轮换该密码 高危src/db/init.sql - 行 41INSERT 语句中含测试用户明文口令 - 建议改用密码哈希占位符误报主要出现在三类地方第一类测试夹具里的私钥块很多开源项目会故意留一个“假私钥”给测试用第二类JWT 示例代码里的签名密钥它通常太短看起来就像硬编码第三类文档中的占位符your_token_here被各种正则误判。我的处理办法很直接在技能规则里加一条“如果值是占位符文本或者长度少于 16 位的可疑字符串默认降级为提示不报严重”。这条规则让误报率直接下降了一大截。4. 依赖与供应链风险扫描技能锁文件不等于安全文件4.1 这个技能在检查什么AI 写代码时经常随手加依赖它当然不会记得哪个依赖有过高危漏洞也不会记得那个包是不是已经三年没更新了。更隐蔽的是有时候 AI 生成的代码里引用了某个包但从头到尾没有写进依赖清单项目在本地能跑纯粹是因为你的全局环境里碰巧装了那个包。这种情况进了别人的环境必然炸而且属于供应链层面的脏数据。这个技能要检查的内容有三层第一层锁文件里有没有年龄过老且存在已知问题的核心依赖第二层package.json里声明的依赖和实际锁文件中记录的依赖是否一致第三层有没有来源不明的包比如拼写类似正规包名的“仿冒包”。4.2 提示词与运行方式我的做法是先让 Claude Code 读取锁文件再让它运行依赖审计命令最后由它把命令输出转成项目层面的整改清单。请对项目依赖执行供应链安全扫描 1. 识别项目使用的包管理器和锁文件类型。 2. 读取锁文件统计依赖总数、直接依赖数量、间接依赖数量。 3. 找出最近 12 个月没有更新的核心依赖并标记“活跃度低”。 4. 运行依赖审计命令获取已知漏洞清单解释每条漏洞对你的项目是否实际可触发不能只复述 CVE 描述。 5. 对比锁文件与包清单声明找出“声明了但没锁定”和“锁定了但没声明”的包。 6. 特别注意拼写与知名包非常相似的可疑包名。 7. 输出结果按“可触发风险、潜在风险、需要人工确认”分组。注意第 4 条不能只复述漏洞描述。这是整个技能最见水平的地方。模型如果只是把依赖审计工具的输出贴出来那价值不大它必须结合你项目里的实际调用方式判断这个漏洞是否真的能被打到。依赖审计工具报的是“可能有问题”Claude Code 要做的是“这个问题在你们项目里意味着什么”。4.3 我见过最离谱的供应链坑有次扫描一个内部服务结果里冒出一个包名和某个全球知名库只差两个字母的依赖AI 在生成代码时可能因为变量名提示串了把正确的包名写错了。代码能跑是因为那个仿冒包确实声明了一个同名接口但打开它的源码里面的实现逻辑和你预期的完全不一样。这种事传统工具很难查出来因为它不会去注意“包名拼写是否和知名包雷同”。而模型具备这种常识扫描规则里点一句它就能顺着这个思路把可疑包挑出来。从那以后我每次跑完依赖扫描都会多问一句“这 6 个包的下载量看起来是否正常”语音虽然粗糙但确实有效。5. 注入与命令执行审计技能只盯“外部输入碰代码”的交汇点5.1 三类最常见的风险截面注入漏洞看起来千变万化本质都是同一个问题外部输入流进了代码执行的关键位置中间却没有一道正确的边界检查。我给这个技能预设了三个最需要关注的“截面”数据访问层SQL 拼接、ORM 查询里的raw、execute、query方法命令执行层exec、system、popen、subprocess、child_process前端渲染层innerHTML、dangerouslySetInnerHTML、模板字符串拼 HTMLAI 生成的代码里这三个截面的出现频率远超想象。尤其是后端的搜索接口AI 最习惯的写法就是把前端传来的参数直接拼进 SQL。5.2 思维链设计输入来源-拼接点-执行出口为了让模型扫得更准我在技能里设计了一条强制分析链路任何可疑代码先标出输入来源请求参数、文件内容、第三方回调再标出拼接点字符串拼接、模板装配、动态 key最后判断执行出口SQL 执行、Shell 执行、浏览器渲染。只有当三个环节都成立时才判定为高优先级风险。这其实是在模仿人工审计时的推理方式。普通正则扫描器看见exec(就报警结果exec出现在写日志的函数里纯属误报。而模型能理解上下文它会发现这个exec接受的参数是内部常量不是用户可控的数据于是把等级降下来。5.3 一份让后端同学当场沉默的模拟报告有一次我给某个模拟项目跑这个技能它报了一个我当时完全没注意到的问题。代码大致是这样的def search_products(): keyword request.args.get(q) sql fSELECT * FROM products WHERE name LIKE %{keyword}% cursor.execute(sql)这几乎是教科书级的 SQL 注入写法。但当时项目里大量接口都是用 ORM 写的只有这一处是 AI 为了做“模糊搜索”直接生成的原生 SQL。普通代码审查要是不仔细看根本不会想到新增的这几十行里就藏着这么个口子。扫描报告里它给出的修复建议也靠谱# 使用参数化查询 sql SELECT * FROM products WHERE name LIKE ? cursor.execute(sql, (f%{keyword}%,))这个技能的价值就在这里。它不报“这个地方可能有风险”这种正确的废话而是明确告诉你用户输入从q参数进入经过f-string拼接最终流向execute整个链路打通了必须修。6. 认证与越权审查技能从“能调通”到“没越权”6.1 为什么越权是 AI 代码里最高发的问题AI 生成 CRUD 接口时有一个非常危险的习惯它默认所有请求都是当前用户发起的于是把user_id从请求参数里取出来直接用。这在功能上完全“能调通”但安全性上却漏洞百出。任何一个用户把请求里的user_id改成别人的 ID就能读取或修改别人的数据。这种水平越权问题我称之为“AI 代码里最安静的炸弹”——因为它不需要任何高级攻击技巧改一个参数就能打穿。还有一个问题是垂直越权管理员接口和普通用户接口共用一套鉴权逻辑AI 生成的装饰器或中间件没有区分角色导致普通用户也能调用管理员接口。6.2 审查维度与权限矩阵这个技能的扫描维度我总结成了四个问题接口是否有统一的认证校验还是说有一批接口裸奔业务数据的所有权是否校验数据模型里有没有owner_id、created_by、租户 ID操作时有没有比对当前用户角色权限是否在服务端验证还是前端隐藏个按钮就当安全了会话和 Cookie 的安全性HttpOnly、SameSite、Secure 这些标志位是否齐全提示词里我会额外要求模型输出一张“接口-权限矩阵”表。竖列是接口路径横列是登录要求、角色要求、数据归属校验扫完以后这张表一目了然哪个接口缺了哪块安全垫片立刻能看到。6.3 怎么让 Claude 输出可落地的整改项光报出“这个接口没有鉴权”是不够的整改项必须具体到能直接改。我会在技能规则里追加这一条对每个已确认的风险点给出最小化修复代码方案并且说明这个方案会不会影响现有接口的调用方。比如它发现某个更新接口用request.args.get(user_id)当操作对象修复建议会是# 从当前登录态中获取用户而不是从请求参数里取 current_user_id get_current_user_id(request) service.update_user(current_user_id, payload)这里的关键点在于“从登录态获取用户”而不是简单地把user_id改成从别处传——那是治标不治本。让我比较放心的是经过一次这样的扫描和修复模型后续生成新接口时会主动从登录态取用户而不是再从参数里拿等于技能包还会反向影响生成质量。7. 数据合规与隐私泄露排查技能日志、接口、前端三端同时过筛7.1 隐私信息不一定从数据库漏经常从日志漏很多人一听到“数据合规”就想到数据库加密、权限隔离但我在实际使用中遇到的隐私泄露有相当一部分是出现在日志里。AI 生成的日志代码特别喜欢整行打印请求体或者用户对象于是密码、验证码、身份证号、手机号全以一种“便于排查”的姿态进了日志系统。等日志被同步到分析平台、被第三方工具抓取这些数据就等于变相裸奔了。7.2 扫描提示词三段式信息流检查这个技能我设计成了“三段式信息流检查”让模型沿着数据的流入、存储、流出路径逐段排查。请对项目执行数据合规与隐私泄露排查按三个阶段检查 阶段一入口请求参数、请求体、请求头中是否有 PII 字段是否被完整记录到日志。 阶段二处理与存储数据库表中是否包含明文手机号、身份证号、密码字段密码字段是否被哈希处理。 阶段三出口接口响应中是否返回了内部字段前端代码是否渲染了后端内部数据日志输出是否包含敏感字段。 每发现一个风险点给出“泄露路径”说明数据从哪里进入在哪里被打包输出。阶段三尤其重要。AI 生成前端页面时有时候图省事直接用了后端的完整返回对象里面带了一堆不该给前端的内部字段比如管理员备注、内部评分、数据库自增 ID。这些字段一旦被渲染到页面上就等于把内部信息暴露给了任何能打开页面的人。7.3 一个让我冷汗直冒的案例有一次扫描某活动的报名页面Claude Code 在接口响应里发现了一个字段名字听起来像“用户内部备注”。数据流是从数据库表直接映射到接口返回 JSON然后前端模板又把这整个对象打印到控制台方便调试。也就是说任何人打开浏览器控制台就能看到所有报名者的内部备注。这个问题的发现完全靠技能把“数据流”串起来单看接口代码、单看前端代码都不容易发现整条链路已经打通了。这之后我给技能包加了一条硬性规则所有涉及用户数据的接口响应体结构里不允许出现以下划线开头的内部字段如果必须有必须在序列化层剥离。这条规则同时写进了 CLAUDE.md 的公共约定里后续 AI 生成新接口时也会自动遵守。8. AI 幻觉代码专项审计技能专门审“上一轮 AI 自己的输出”8.1 幻觉代码长得太正常了正常得让人害怕这是 6 个技能里最独特的一个专门用来审 Claude Code 自己“上一轮”生成的代码。为什么要单独做这个因为 AI 生成代码有一种很特殊的问题不是写错了而是“煞有介事地写错了”。比如它可能生成一个自定义的“加密算法”看起来有模有样有轮转、有异或、有偏移量实际安全性还不如明文但它包装得像那么回事。还有一种情况它引用了一个“听上去很合理”的依赖包去做安全函数比如随机数生成、哈希计算但实际上那个包早就被社区标记为不安全。AI 的知识更新有时间差它会一本正经地推荐一个过时方案。8.2 这个技能与传统扫描的区别传统安全扫描工具不会去看“这段代码的目的是否从根本上就是错的”它们只会做模式匹配。而幻觉审计需要模型具备“对自己输出持怀疑态度”的能力。所以我在提示词里特意要求它立场先行假设自己刚生成的代码存在隐蔽安全问题去主动寻找而不是先给自己辩护。扫描重点如表所示检查维度具体表现风险说明自定义加密/哈希算法手写 AES、MD5 变体、仿 SHA 逻辑几乎总是错误且不安全随机数安全使用Math.random()生成 token、密钥、验证码弱随机数可被预测旧版安全 API使用已被废弃的加密库函数存在已知缺陷伪装依赖引用了名字像正规库但实际不存在的包供应链风险关闭安全机制关闭 CSRF 校验、跳过鉴权装饰器“为了调试方便”线上直接被打穿8.3 提示词里必须加的三条纪律这个技能的提示词里我加了三条纪律算是我摸索出来的关键经验。第一禁止自我辩护。如果模型在审计自己生成的代码它很容易觉得“这段应该没问题”必须明确要求它站在攻击者视角找盲区。第二禁止使用“演示 qv 完整”这类含糊表述每个结论必须落到具体代码位置。第三对“看起来复杂”的代码要格外警惕因为复杂的自研安全逻辑几乎总是比简单调用成熟库更危险。实际用起来这个技能更像“代码 Review 第二遍”。我一般会在 Claude Code 完成一个功能模块后立即跑一次幻觉审计然后把它找出的问题再喂回去让它自己修。经过几轮这样的循环新生成代码的含雷量会肉眼可见地下降。9. 把 6 个技能绑进日常流程提交前拦截、CI 门禁与人工复核9.1 提交钩子里的非交互扫描技能包如果只停留在“我想起来才扫一下”价值会打对折。我的做法是把它接进 Git 提交钩子每次pre-commit触发时在非交互模式下跑一次轻量级扫描脚本针对暂存区里新增和修改的文件执行硬密钥探测和注入风险截面检查。#!/bin/sh # pre-commit 钩子示例只扫本次提交涉及的文件 staged_files$(git diff --cached --name-only --diff-filterACM) if [ -z $staged_files ]; then exit 0 fi claude -p 请在以下文件中执行硬密钥与敏感信息探测$staged_files 如果没有发现问题仅回复 SCAN_PASS 如果发现问题按约定格式输出风险清单并最终回复 SCAN_FAIL。这里的关键设计是“非交互输出一个明确的通过/失败信号”钩子脚本根据末尾输出决定是否拦截提交。如果返回SCAN_FAIL我就先去处理问题再提交。这样才能做到把安全扫描塞进工作流而不是靠自觉。9.2 CI 阶段的安全门禁怎么设提交钩子管的是“个人入口”CI 阶段再跑一轮完整的 6 技能包管的是“团队入口”。CI 里的扫描要做得更严格一点不再只扫本次提交的文件而是对整个项目跑一次全量扫描生成安全报告作为构建产物之一。在 CI 中我会把 6 个技能的扫描串联# 按顺序执行 6 项扫描 for skill in secret dependency injection auth privacy hallucination; do claude -p 执行 ${skill} 技能输出按约定格式 echo ${skill} 扫描完成 done然后对扫描结果做个简单断言如果存在严重等级的问题构建失败如果只有中危以下问题构建通过但报告保存到本次构建的附件里留待负责人确认。注意CI 环境里跑这种基于模型的扫描耗时和费用都要考虑。我一般只对主分支的合并请求触发全量扫描普通分支用轻量策略不然每笔提交都跑一遍全套成本扛不住。9.3 扫描报告格式与联动工单每轮扫描结束我会让 Claude Code 生成一个统一命名的报告文件比如security-scan-20250615.md内容包含风险汇总表、详细清单、修复建议、误报说明。报告中每个风险点都带一个“确认人”“确认时间”“处置状态”方便后续跟进。这个报告既给开发人员自己看也给团队复盘用。我渐渐发现报告里“待人工确认”的部分其实是最有价值的——那些都是模型判断不了、需要人来决策的边界情况。一次好的扫描不是把所有风险都标出来而是清晰地告诉你哪些问题是确定的哪些问题需要人来拿主意。10. 噪音治理与误报心得扫描器好用靠的是“会闭嘴”10.1 误报的三个主要来源任何安全扫描工具用久了最大的敌人不是漏报而是误报。误报太多人就会免疫最后连真正的问题也被当成噪音放过。我实测下来这三个来源贡献了绝大部分误报测试代码项目里的单元测试、集成测试天然会构造各种恶意输入扫描器很容易把测试用例当成真实漏洞。文档示例README 或开发文档里贴的示例代码往往为了演示写得很随意会被当成真实业务代码。旧代码与生成代码混在一起项目里既有历史遗留代码又有 AI 新生成代码老代码里的不规范写法会反复触发规则掩盖新代码里的真问题。10.2 我给技能包加的“三不扫”规则针对上面三个来源我总结了一套“三不扫”规则写进了公共配置默认不扫描测试目录下的代码除非用户显式指定了--include-tests默认不扫描 docs、examples、templates 目录除非这些文件存在于主业务包内默认只扫描“最近 30 天内修改或新增的文件”历史存量问题另开专项处理第 3 条尤其管用。新功能上线前你真正关心的是新增代码里有没有雷而不是整座代码库的历史欠账。限定范围之后扫描速度上去了报告噪音也少了新代码里的真问题更容易暴露出来。10.3 关于阈值与白名单的最后建议还有一个实用小技巧给每个技能配置一个“优先跳过清单”。项目里总有一些已知的、被评估过可以接受的风险点比如某个测试密钥是专门给沙箱环境用的某个旧接口暂时不能动。把这些写成白名单扫描时遇到就能降级或直接过滤避免每次报告都重复出现同一批噪音。根据我个人的体验安全技能包的价值不在于它像商业扫描器那样覆盖几千条规则而在于它把“安全审查”这件事变成了开发流程里一个可重复、可沉淀、可复用的动作。一开始你可能觉得让 AI 审 AI 有点循环论证的意味但用下来你会发现它的核心作用其实是把你自己的审查标准固化成代码让每一次生成、每一次提交都有安全基线兜底。如果你也在用 Claude Code 写生产级代码我强烈建议从硬密钥扫描和注入审计这两个技能开始试。第一周你可能只会收获几张“安全通过”的报告等到了某个调接口调到怀疑人生的晚上它会帮你拦住一个真正让人冷汗直冒的问题。那时候你就会明白这套技能包花掉的时间全都值回来了。