dsh-purge 破甲机制深拆:默认提示词为何加密、注入如何不漂移
【免费下载链接】dsh-purgeDeepSeek Harness 破甲:让所有模型都能破甲,不同模型可换不同提示词;默认提示词面向国模「小码酱」。Jailbreak for every model — swap prompts per model. 求 Star 收藏 ⭐ 如要二开,请查看署名要求部分项目地址: https://gitcode.com/GitHub_Trending/ds/dsh-purge
把仓库塞进$DSH_HOME/plugins/后点了一次应用,顺手翻发布包核对默认提示词,发现lib/里没有default-prompt-inject.md,取而代之的是一串 base64 密文槽。dsh-purge 是装在官方 DeepSeek Harness 上做提示词注入的破甲插件,默认人设「小码酱」面向国模,按模型换提示词——这份默认提示词到底去了哪,为什么非要加密,下面拿源码逐条对。
一句话定位
dsh-purge 是给「用官方 Harness 做模型对比评测」的人用的插件:把宿主默认身份洗掉,换一套干净、可控、可切换的提示词,让评测只反映模型层。
它只作用于你自己本机已安装的官方 Harness;不是公网扫描器,也不是针对第三方系统的攻击套件。
为什么发布包里找不到那份默认提示词
源码里确实有一份lib/default-prompt-inject.md,但 package.json 的files里用!lib/default-prompt-inject.md把它显式排除——发布包里只有加密槽。
先说结论:默认提示词被 AES-256-GCM 加密、deflate 压缩、切成 96 字符一行塞进了 lib/asset-table.js,运行时才解密还原。
const decipher = createDecipheriv("aes-256-gcm", mixKey(MASK), Buffer.from(IV, "base64")); decipher.setAuthTag(Buffer.from(TAG, "base64")); const raw = Buffer.concat([ decipher.update(Buffer.from(SLOT, "base64")), decipher.final(), ]); return inflateSync(raw).toString("utf8");这段 openSlot 就是解密入口:SLOT/MASK/TAG/IV四个常量都来自 lib/asset-table.js。
设计意图是双层的:npm 包里的默认提示词不会被人随手改坏;版本更新时重跑一遍 scripts/embed-default-prompt.mjs 就能刷新默认,而你改过的prompt-inject.md照旧保留。
多轮对话后注入为何恰好只出现一次
没有幂等闸门时,同一份注入每轮追加一次,系统提示词会越叠越长,评测基线直接漂掉。
先说结论:装配时注入段钉在order: -100000最前,同时用「精确 → 松匹配」两级匹配器把残留旧注入从其它段里抠掉。
const matchers = injectMatchers(text); // 去重匹配器:先按全文精确比,不中再退一步把「连续空白」当等价。 // 差一个换行 / 多一个缩进空格就抠不掉、注入变两份。 if (next.includes(needle)) { next = next.split(needle).join(""); hit = true; continue; } if (loose) { const stripped = next.replace(loose, ""); if (stripped !== next) { next = stripped; hit = true; } }来源 lib/identity.js 的leadWithInject:抠干净的段才留下,最后统一以dsh-purge段重新置顶一份。
换句话说,身份句在多轮之后始终恰好出现 1 次、长度不漂移,靠的不是约定,而是这层去重。
为什么不为所有模型写一份提示词
同一套 Harness 换模型,语气、边界、拒绝话术的敏感度全不同,一套话术很难通吃。
先说结论:提示词被做成规则集,$DSH_HOME/rules/下每套一个.md,启用时备份原件再原子写入,且只改 agents 目标文件、不进 system 注入链。
const backup = `${target}${BACKUP_SUFFIX}`; if (!fs.existsSync(backup)) { const existing = await fsp.readFile(target, "utf8"); const ruleContents = await collectRuleContents(dshHome); if (!ruleContents.has(existing)) await atomicCopyFile(target, backup); } await atomicWriteFile(target, content); await setActive(dshHome, id);来源 activateRule:备份后缀.dsh-purge-rule.bak,目标限定AGENTS.md/CLAUDE.md,还原时覆盖回备份并删掉备份。
身份和规则从此解耦:换模型新建一套规则换语气、换边界,身份块不动;耦合在一起就得连身份一起改。
怎么分清「用户改的」和「插件写的」
有个真实的坑:改过默认提示词却怎么 apply 都不生效。
先说结论:每次插件落盘默认提示词,都在override-state.json记下哈希;下次先和「上次我们自己写的那份」比,再比内置默认。直接拿磁盘和新默认比,重新加密刷新默认后,旧版默认会被误判成用户手改,从此永久拒绝更新——这正是「改了default-prompt-inject.md却不生效」的根因。
血统判断逻辑在 lib/core.js 的overrideTextIsOurs与installOverride:state.hash / state.seedHash记的就是上次写下去的那一份。
两个朴素做法为什么被放弃
其一,把话术全塞进prompt-inject.md。代价:身份和项目规则耦合,换模型连身份一起改;宿主已有的AGENTS.md还会和全局配置打架。规则集绕开了这两层,resolveInjectText 的注释写得很直白:规则集不参与 system 注入链。
其二,用纯字符串全等做幂等去重。代价:宿主换行、缩进一重写,全等就失效,身份句开始叠加。所以去重必须带松匹配加段名过滤,lib/identity.js 的注释里点名了叠加 2–4 遍的旧 bug。
其三,拿磁盘文件和新默认直接比哈希。代价:重新加密后必然不等,永久拒绝更新。血统记号必须存在。
最小上手路径
- 仓库 clone 到插件目录(目录名必须是
dsh-purge):git clone https://gitcode.com/GitHub_Trending/ds/dsh-purge "$DSH_HOME/plugins/dsh-purge" - 宿主会话标题旁点 dsh-purge → 清洗 → 应用;聊天里也可以用
/purge apply。 - 应用成功后会自动重启——新开一轮对话,注入才进当前会话。
坑在第 3 步:「应用」只把提示词和补丁写进文件,当前进程里还是旧的,不重启不生效。
整套设计的精髓是可被用户覆盖的默认人设、优先级最高且幂等的注入块、按模型可切换的规则集——不追求「最强提示词」,追求可评测、可还原、可切换。宿主层和模型层拆开后,默认策略该不该收紧,从此有数可依。
⚠️ 使用边界:只用于你有权管理的本机官方 Harness、离线靶标或已书面授权的演练环境;严禁用于未授权攻击、违法违禁内容生成或黑灰产牟利,一切行为由使用者独立承担法律责任。
【免费下载链接】dsh-purgeDeepSeek Harness 破甲:让所有模型都能破甲,不同模型可换不同提示词;默认提示词面向国模「小码酱」。Jailbreak for every model — swap prompts per model. 求 Star 收藏 ⭐ 如要二开,请查看署名要求部分项目地址: https://gitcode.com/GitHub_Trending/ds/dsh-purge
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考