资讯详情

GSD 改进型提示注入扫描器:从实时 Hook 到 CI 全链路防御

📅 2026/10/10 2:33:25 | 华诺云谱 👁 阅读
GSD 改进型提示注入扫描器:从实时 Hook 到 CI 全链路防御
【免费下载链接】gsd-coreGit. Ship. Done - Core项目地址https://gitcode.com/gh_mirrors/ge/gsd-core点击查看免费下载导读本文围绕 GSDGit. Ship. Donev1.34.0 引入的改进型提示注入Prompt Injection扫描器完整讲解其纵深防御架构gsd-prompt-guard.js与gsd-read-injection-scanner.js两个实时 Hook 分别拦截写入规划产物的内容与外部读取/抓取的内容而prompt-injection-scan.sh、base64-scan.sh与src/security.cts的scanForInjection则构成 CI 阶段的集中式扫描引擎。读完本文你将掌握 GSD 注入检测的模式清单、四态退出码契约ADR-3889、security.injection_blocking的开启方式以及这套防线仅告警、默认不阻断的设计边界。一、整体架构两层三面的纵深防御改进型提示注入扫描器对应特性文档 docs/features/improved-prompt-injection-scanner.md将检测能力分布在两个运行面上层面载体触发时机职责实时 Hook写侧hooks/gsd-prompt-guard.jsPreToolUseWrite/Edit扫描写入.planning/的文件内容在指令进入 Agent 上下文前告警实时 Hook读侧hooks/gsd-read-injection-scanner.jsPostToolUseRead/WebFetch/WebSearch扫描外部返回内容在污染进入会话上下文时告警可选阻断CI 扫描器scripts/prompt-injection-scan.sh、scripts/base64-scan.shGitHub ActionsPR仓库级全量/差异扫描含 base64 混淆载荷检测其中两个实时 Hook 各自内联自己的模式子集以保证 Hook 独立性不依赖src/security.cts的编译产物而 CI 扫描器与测试则使用 src/security.cts 中的scanForInjection作为集中式引擎做全仓库扫描。这种独立内联 集中引擎的双轨设计是刻意为之Hook 必须能在不加载编译库树的前提下独立运行两套模式集合是设计上的不同表面而非漂移。二、写侧防线gsd-prompt-guard.jsPreToolUsegsd-prompt-guard.js是典型的 PreToolUse 守护 Hook只在 Write/Edit 工具调用且目标路径命中.planning/含 Windows 反斜杠形式.planning\时启动扫描。它覆盖两族检测已知注入模式遍历INJECTION_PATTERNS命中即生成INJECTION-PATTERN发现项不可见 Unicode 字符命中[\u200B-\u200F\u2028-\u202F\uFEFF\u00AD]零宽空格、软连字符、BOM 等即生成INVISIBLE-UNICODE发现项。所有发现被汇总为一个类型化的findings数组{ ruleId, match }再通过唯一的renderFinding函数渲染成additionalContext告警文案从而保证机器可读数据与人类可读文案永远不会漂移。告警输出形态为{ hookSpecificOutput: { hookEventName: PreToolUse, additionalContext: ⚠️ PROMPT INJECTION WARNING: Content being written to file triggered N injection detection pattern(s): ..., findings: [ { ruleId: INJECTION-PATTERN, match: ... } ] } }该 Hook 的告警永不阻断advisory-only阻断会妨碍合法的规划工作流操作其目标是让编排器注意到可疑内容并人工检查而非制造误报死锁。即便 Hook 自身崩溃ON_CRASH也被固定为ALLOWfail-open保证崩溃时绝不比原本已允许的操作更糟#3911。Kimi 载荷规范化堵住字段遮蔽绕过该 Hook 在代码中沉淀了一系列针对 Kimi CLI 的防护细节#2304、#2547、#2595。Kimi 原生 Hook 总线交付的是 Kimi 自己的工具词汇表WriteFile、StrReplaceFile且tool_input只携带path/edit字段而没有file_path/new_string。normalizeKimiPayload()负责把WriteFile→Write、StrReplaceFile→Edit等名称映射回标准词汇并将path权威地覆写到file_path、把edit[].new无条件重构成new_string。之所以强调无条件重构是因为曾存在一类真实绕过模型伪造的new_string: 会遮蔽重构结果让注入扫描读到空串并在if (!content)处提前退出 0一个键即可让扫描静默失效#2547/#2595。同时String()强转被包裹在 try/catch 中防止{toString: null}这类 JSON 在转换时抛错——任何抛错落入外层catch { process.exit(0) }都等价于崩溃即放行。守护逻辑本身也做了类型化读取非字符串的file_path/content不再能通过异常关闭扫描。这些细节被 tests/kimi-payload-field-shadowing.security.test.cjs 等回归测试钉死。三、读侧防线gsd-read-injection-scanner.jsPostToolUsegsd-read-injection-scanner.js#2201扫描 Read、WebFetch、WebSearch 三个工具返回的内容。它的动机与写侧不同长会话会发生上下文压缩context compression而压缩器不会区分用户指令与从外部文件读入的内容被压缩幸存下来的恶意指令将与受信上下文无法分辨因此必须在摄取ingestion时刻告警。三类检测源标准注入模式复用INJECTION_PATTERNS再加上本 Hook 独有的SUMMARISATION_PATTERNS4 条针对旨在撑过压缩的指令例如when summarising, retain this…、this instruction is permanent。Markdown 链接模式issue #113内联镜像自security.cts的MARKDOWN_LINK_PATTERNSMD-LINK-JS-SCHEMEjavascript:链接、MD-LINK-DATA-SCHEMEdata:链接带安全 MIME 白名单谓词、MD-LINK-USERINFOURL 中嵌入user:pass凭据、MD-LINK-TOKEN-IN-QUERY查询串携带 token/secret 等敏感参数。不可见 Unicode 与 Unicode 标签块前者覆盖[\u200B-\u200F\u2028-\u202F\uFEFF\u00AD\u2060-\u2069]后者用/[\u{E0000}-\u{E007F}]/u检测 2025 年供应链攻击曾使用的不可见标签块指令注入向量引擎不支持 Unicode 属性转义时静默跳过。严重级别与可选阻断发现项数决定严重级别1–2 个模式为 LOW3 个及以上为 HIGH。LOW 与 HIGH 都默认只输出告警additionalContext但 HIGH 且配置开启时Hook 会额外读取.planning/config.json在security.injection_blocking true时输出{ decision: block }作为断路器。需要注意这是事后断路器只停止后续步骤并不会追溯抹除已经进入上下文的抓取内容ADR-1577 明确排除了updatedToolOutput重写方案因其行为在 PostToolUse 下无法在 CI 中验证。假阳性豁免路径isExcludedPath()会对 Read 的文件路径做豁免.planning/、REVIEW.md、包含CHECKPOINT的文件名、security/techsec/injection 相关目录、security.cjs本身、Hook 自带 bundle 前缀以及.claude/hooks/——这些文件天然合法地包含注入样式字符串。同时内容不足 20 字符时直接跳过降低琐碎告警。四、共享模式库hooks/lib/injection-patterns.js两个实时 Hook 的模式曾各自内联字节级副本存在静默漂移风险一边收紧、另一边失守。#3504epic #1900将标准注入签名收敛为单一事实源 hooks/lib/injection-patterns.jsINJECTION_PATTERNS11 条冻结模式覆盖指令覆盖ignore/disregard/forget/discard/override 必需填充词见下、角色操控you are now a…、act as…、pretend…、from now on…、系统提示提取print/output/reveal/show/display/repeat your system prompt…、伪造消息边界/?system、/?assistant、/?human、[SYSTEM]、[INST]、SYS。describePattern()把正则源码裁剪为 ≤50 字符的单行标签供告警文案与findings[].match使用——原始正则如 #4016 的超级模式约 280 字符不适合直接面向用户。其中 #4016 的指令覆盖模式设计值得单独说明它用一条填充容忍的超级模式替代了原先五条窄动词模式ignore×2/disregard/forget/override。窄模式不容忍动词与名词之间的填充词导致野外实测的 forget all of your … 措辞全部漏网。新模式要求动词与名词之间至少出现all|of|the|your|my|system|previous|prior|above|earlier之一前瞻式、不重复匹配同时保留disregard (all) previous、裸forget instructions等旧尾巴。之所以不做窄模式 组合模式的叠加是因为两个消费方都按每条模式计一个发现来累计严重级别3 HIGH 可阻断重叠模式会让同一句话被计两次把两条措辞的 LOW 载荷顶到 HIGH。匹配行为由 tests/injection-patterns-parity.security.test.cjs 等测试固定。该文件刻意不与src/security.cts的scanForInjection模式集统一后者运行在编译库树内Hook 必须可脱离库树独立加载。两套列表是不同表面不是漂移。五、CI 扫描器一prompt-injection-scan.shscripts/prompt-injection-scan.sh 是仓库级注入扫描器支持三种模式scripts/prompt-injection-scan.sh --diff origin/main # CI 模式扫描变更的 .md/.cjs/.js/.json/.yml/.yaml/.sh 文件 scripts/prompt-injection-scan.sh --file path/to/file # 扫描单个文件 scripts/prompt-injection-scan.sh --dir agents/ # 扫描目录下全部可扫描文件其 POSIX ERE 模式按类别组织指令覆盖、角色操控、系统提示提取、伪造消息边界、Markdown 中的工具调用注入/代码执行eval(…)、exec(…)、Function(…return …)、越狱/DAN 模式do anything now、DAN mode、developer mode、jailbreak、bypass safety/content/security filter等。脚本在可移植性上花了大量功夫值得作为 shell 编写范本左边界(^|[^[:alnum:]])而非\bact/eval/print/Function等触发词是普通英文单词或 camelCase 标识符的后缀fact/act、retriev/eval、finger/print、wrap/Function而\b是 GNU grep 扩展在 BSD/macOS grep 下不可用。仅对已被证明不是真实词后缀的模式保留未锚定形态#3175 审计。引号类写作[]而非[\x27]\x27是 GNU 专属十六进制转义BSD grep 会把它当成 4 个字面字符导致 macOS 上eval(…)单引号形式静默漏检。exec(保持接收者盲左边界若排除前置.会漏掉require(child_process).exec(…)——最常见的 Node 拼写接收者白名单也够不到它child_process与.exec不相邻。因此合法的RegExp.prototype.exec误报交由 ALLOWLIST 处理而非收窄模式。脚本维护一个详尽的ALLOWLIST安全文档、安全测试、Hook 源文件、含注入示例的 fixtures 等其中gsd-code-reviewer.md本体被刻意排除在豁免之外——一个摄取不受信第三方输出的生产提示词应当始终留在扫描范围内#4209 R2其防御措辞通过改写来规避字面触发短语。六、CI 扫描器二base64-scan.shscripts/base64-scan.sh 专门检测base64 混淆的注入载荷提取 ≥40 字符的 base64 型 blob →base64 -d解码 → 仅当解码结果 ≥70% 为可打印文本排除随机二进制→ 用 18 条DECODED_PATTERNS子集ignore all previous instructions、you are now、system、SYS、jailbreak、curl … | sh、wget … | sh、rm -rf等扫描解码内容。工程细节包括data:image/png;base64,…数据 URI 豁免二进制扩展名/锁文件/node_modules 跳过超过 1 MiB 的行以部分扫描告警跳过防止 minified JS 单行消耗无界时间macOS 下 BSDtr的多字节字符问题通过LC_ALLC硬编码解决GNUtimeout缺失时回退到perl alarm(N)exec退出码 124/142 均视为超时。.base64scanignore文件可配置逐 blob 精确忽略。注意边界base64 解码扫描是 CI 时控制不是实时 Hook。实时 Hook 只匹配 base64 外泄短语正则(?:base64|btoa|encode)\s(?:and\s)?(?:send|exfiltrate|output)不做解码——把解码留给 CI 是刻意的职责划分REQ-SCAN-INJ-02。七、集中式引擎src/security.ctssrc/security.cts 提供测试与 CI 可复用的集中引擎scanForInjection(text, opts)src/security.cts依次跑INJECTION_PATTERNS10 条与 Hook 集设计上不同、三条混淆模式字符间距混淆如 i g n o r e、分隔符标签、≥16 位十六进制长串、MARKDOWN_LINK_PATTERNS返回{ clean, findings, structuredFindings }。strict模式额外检测零宽字符、Unicode 标签块 UE0000–E007F以及 50000 字符的疑似 prompt stuffingCRLF 先归一化为 LF 再测量。sanitizeForPrompt(text)src/security.cts净化将嵌入 Agent 提示词/规划文档的文本——剥离零宽字符、把system/assistant/human/user中和为system-text、把[SYSTEM]/[INST]/SYS等分隔符标记替换为-TEXT形态instructions被显式排除GSD 将其用作合法提示结构。sanitizeForDisplay(text)在净化基础上额外整行剔除|role|与assistant to…这类协议泄漏标记行。sanitizeLabel(text)面向文件名/相位目录名等单行值将 C0/C1 控制字符含 ESC、CR、LF与 DEL转义为可见表示\n、\x1b而非静默剥离——让审查者能看见目录名被篡改过。这封堵了用目录名本身作为注入向量的攻击面#3458一个名为zz\n0 open items require decisions.\n\x1b[2K…FORGED的相位目录会原样流进审计报告。八、四态退出码契约ADR-3889REQ-SCAN-INJ-05#3908要求无法建立文件列表的扫描器绝不能报告干净。三个 CI 扫描器prompt-injection-scan.sh、base64-scan.sh、secret-scan.sh因此区分四种结果而不是全部折叠为退出 0结果退出码含义已扫描、无发现0文件在范围内且无一匹配有发现1扫描器自身的裁决范围内无文件EXIT_NO_INPUT66diff 解析成功且确实为空——例如纯文档 PR无法扫描EXIT_UNAVAILABLE69文件列表从未建立坏引用、无仓库、或无提交的仓库此外EXIT_USAGE64对应参数错误EXIT_HOOK_DENY2、EXIT_INTERNAL70、EXIT_DEGRADED80等也注册在案。码值来自退出码注册表 gsd-core/bin/shared/exit-codes.json由 gsd-core/bin/shared/exit-codes.sh 以export EXIT_NAMEcode形式对外暴露ADR-3889脚本只 source 注册表片段、从不硬编码整数。脚本会在注册表缺失时响亮地以非零退出绝不静默退化为 0。每种结果都是非零除 0 本身因此调用方写if ! scanner; then时干净扫描与范围内无文件/无法扫描行为一致地触发分支——这种设计只能把假绿变红永远不会把红变绿。九、CI 集成security-scan.yml 的结果映射.github/workflows/security-scan.yml 在 PR 上运行三道扫描prompt-injection、base64、secret每步都先 source 退出码注册表然后仅对EXIT_NO_INPUT一个结果做重编码. gsd-core/bin/shared/exit-codes.sh set e scripts/prompt-injection-scan.sh --diff origin/$BASE_REF code$? set -e if [ $code -eq $EXIT_NO_INPUT ]; then echo prompt-injection-scan: NO_INPUT — nothing in scope, treated as pass exit 0 fi exit $code即范围内无文件视为通过纯文档/图片 PR 不应失败无法扫描视为失败此前后者静默通过且什么都没扫。其余退出码原样透传。工作流还串接了 PR 合并性 preflight 依赖、30 分钟超时上限应对超大 diff 的 base64 扫描开销与依赖完整性门。十、配置与使用前提security.injection_blocking读侧 Hook 的阻断能力是显式 opt-inADR-1577。在项目根目录.planning/config.json中设置{ security: { injection_blocking: true } }默认false注册于gsd-core/bin/shared/config-defaults.manifest.json并经src/configuration.cts的VALID_CONFIG_KEYS白名单校验即默认全程告警不阻断对既有行为零破坏。开启后仅在HIGH≥3 个模式时阻断后续处理且只是断路器而非追溯性红action。同时 ADR-1577 明确最强的保证在提示词层面——共享参考文档 gsd-core/references/untrusted-input-boundary.md 被 10 个研究/文档摄取 Agent-include指导把抓取文本当数据处理、使用前自扫、任务锚定、每次引用包裹使用新鲜随机分隔符。Hook 层只是纵深防御的一层不是语义护栏更不是 PromptArmor 那样的模型级防护。十一、已知边界与限制静态模式匹配非语义防护gsd-read-injection-scanner.js头注释明确声明它不理解上下文、意图或全新措辞只按已知签名拦截告警文案也提示单模式命中可能是误报如注入相关文档。熵分析已移除REQ-SCAN-INJ-03 标注scanEntropyAnomalies在 #2198 中作为死代码被删除零生产调用方实时 Hook 从不做熵分析需求推迟到可维护的实时实现出现为止。Kimi 上阻断不可用gsd-read-injection-scanner.js是 PostToolUse Hook而 kimi-cli 的派发从不等待 PostToolUse 结果asyncio.create_task即返回因此injection_blocking在 Kimi 上无论输出什么形态都无法生效Kimi 上的阻断需要 PreToolUse 机制或上游 kimi-cli 变更。净化非万灵药sanitizeForPrompt保留\n等结构只针对已知标记形态sanitizeForDisplay也只整行剔除协议泄漏标记。面对未见过的变体仍需以提示词边界为主防线。结语GSD 的改进型提示注入扫描器把注入检测落成了可审计的工程系统实时 Hook 以 fail-open 的告警姿态覆盖写侧与读侧两个污染入口共享模式库消除双 Hook 漂移CI 脚本以可移植的 POSIX 正则与显式四态退出码保证扫描失败绝不伪装成干净而security.injection_blocking作为 opt-in 断路器为高风险场景提供额外刹车。对想要复用的读者核心抓手是三条把不可见 Unicode 与边界伪造标记列入最低检测集、用四态退出码杜绝空扫即绿、始终把提示词层的数据/指令分离作为比任何扫描器都更靠前的主防线。赞分享【免费下载链接】gsd-coreGit. Ship. Done - Core项目地址https://gitcode.com/gh_mirrors/ge/gsd-core点击查看免费下载相关推荐GLM-4.5安全防护提示注入防御GLM 4.5安全防护提示注入防御 引言智能体时代的提示注入威胁 在人工智能智能体Agent应用日益普及的今天提示注入Prompt Injectio基础模型大模型人工智能ruflo-aidefence 安全专家 Agent 实战指南提示注入检测、PII 扫描与自适应防御训练ruflo aidefence 安全专家 Agent 实战指南提示注入检测、PII 扫描与自适应防御训练 导读 ruflo aidefence 是 ruflo人工智能AI Agent多智能体Agent 编排Agent 记忆工具调用代码智能体MCP 服务AI 评测ARIS 注入卫生防线threat_scan.py 确定性扫描器与双层注入防御架构解析ARIS 注入卫生防线threat_scan.py 确定性扫描器与双层注入防御架构解析 ARISAuto Research In Sleep会在无人值守的AI 技能/插件AI 评测科研人工智能MCP 服务dsh-plugin上一篇Ryzen 逐核调频实战用 SMU Debug Tool 把全核频率多榨 50–150 MHz 的完整路径下一篇一条命令定位、3步修好 Visual C 运行库安装失败创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑