- 应用安全
- 漏洞扫描
- 人工智能
- AI Agent
【免费下载链接】deepsec
Deepsec is a security harness for finding vulnerabilities in your codebase powered by coding agents
Deepsec 在将扫描候选文件交给编码 Agent 做安全研判前,会先把"系统提示词半区"组装成一份完整、可复现、可快照的 prompt。本文以仓库中prompt-samples/08-with-info-and-append.md这一份真实样例为解剖对象,讲解项目级 INFO.md 与config.json:promptAppend两块用户自定义上下文在组装 prompt 中的确切位置、它们如何与核心提示词、技术栈威胁要点、漏洞 Slug 笔记协同工作,以及为什么 Agent 层不会把它们重复发射——读完你既能看懂任意一份 prompt 样本的来龙去脉,也能在自己的项目里正确配置这两类上下文。
这份样例在验证什么
先看样例文件头部注释给出的"场景元数据"(prompt-samples/08-with-info-and-append.md第 1-10 行):
- 场景名:
08-with-info-and-append - 场景描述:Next.js 批处理 + 项目 INFO.md +
config.json:promptAppend附加说明——展示它们在组装后 prompt 中的位置,并确认不会由 Agent 层二次发射 - 检测到的技术标签:
["nextjs","react"] - 批处理文件:
["app/secrets.tsx"] - 批处理语言:
["typescript"] - 批处理 Slug:
["xss","secret-in-fallback"] - 生成者:
packages/processor/src/__tests__/prompt-samples.test.ts - 重新生成命令:
UPDATE_PROMPT_SAMPLES=1 pnpm test:unit
这些元数据不是手写的,而是测试代码根据场景定义动态推导出来的:批处理语言由文件扩展名推导,批处理 Slug 由候选匹配的vulnSlug去重得到(见 场景定义 中的scenarioBatch()与languagesForBatch())。也就是说,这份 .md 文件不是"示例文案",而是当前代码实际会生成的确切 prompt 的确定性快照,由测试逐字节比对校验。
组装后的完整结构:一份 prompt 的两个半区
prompt-samples/08-with-info-and-append.md从第 12 行起就是模型最终收到的完整 prompt。它由两个半区拼接而成,对应生产链路中的两个函数:
- 组装半区(system prompt 部分):由
assemblePrompt()生成,见 assemble.ts; - Agent 层包装(任务部分):由
buildInvestigatePrompt()追加目标文件列表、调查步骤与 JSON 输出规范,见 shared.ts。
测试中fullPromptFor()正是按生产路径的顺序把两步串起来:detectTech()得出标签 →assemblePrompt()组装系统提示词半区 →buildInvestigatePrompt()包上文件列表(见 prompt-samples.test.ts)。下面按实际出现顺序逐段拆解。
1. 核心提示词:与具体项目无关的通用底盘
样例开头的"世界级安全研究员"角色设定、严重级别分类(CRITICAL/HIGH/MEDIUM + HIGH_BUG/BUG)、已知漏洞类别总表、误报规避指南、认证绕过模式清单、作用域外文件说明,全部来自CORE_PROMPT常量,定义在 core.ts。这份内容刻意保持精简:"任何只属于某一个框架的内容都必须放进 highlights,而不是这里"(core.ts 第 7-8 行的注释)。
值得注意的细节:核心提示词里的"Known Vulnerability Categories"表格列了 30 多个 slug(auth-bypass、xss、sql-injection、ssrf、secret-in-fallback……)以及other-*通配后缀,告诉模型"扫描器只看这些模式,但你要全看"。这份样例中批处理的xss与secret-in-fallback两个 slug 都出现在表内,属于该批次的"已知类别"。
2. 技术栈威胁要点:只注入检测到的技术
样例的## Threat highlights for this repo's tech stack一节只包含Next.js与React两个小节,没有 Django、Laravel 等内容——因为场景的detectedTags就是["nextjs","react"]。这正是assemblePrompt的按需注入逻辑:renderFrameworkSection()只渲染detectedTags中能查到的 highlight(assemble.ts 第 83-89 行)。
更细一层的控制是batchLanguages语言过滤:highlightForTag()返回的每个TechHighlight都声明了适用的语言集合,只有当批处理文件的语言与该集合有交集时,该技术的 highlight 才会进入 prompt。所以在一个 Next.js + Django 的 polyglot 仓库里,纯 Python 批处理只会带 Django 的要点,不会带 Next.js 的。本场景是["nextjs","react"]标签 +typescript批处理语言,两者吻合,两个 highlight 都正常注入。
这一节还受 6000 字符的预算上限约束:FRAMEWORK_SECTION_CHAR_BUDGET(assemble.ts 第 14 行),超过后整节退化为一行"这个仓库使用了 N 个已知框架……"的摘要,避免撑爆模型上下文(对应场景07-overflow-fallback.md)。
3. Slug 专项评审笔记:只出现本批次命中的 slug
## Slug-specific reviewer notes一节只有两行:
xss:检查每一步的转义状态;裸拼接进 HTML、script 中未转义</的 JSON、ref.innerHTML是常见 sink;secret-in-fallback:process.env.X || "hardcoded"才是 bug——只有当 fallback 看起来像真实凭据时才标记,"localhost"不算。
这两条来自 slug-notes.ts 的SLUG_NOTES表,且只有出现在当前批次的 slug 才会被拉进来(renderSlugSection(),assemble.ts 第 122-133 行)。SLUG_NOTES表内有 150+ 条笔记,但每次只渲染命中项,prompt 长度随扫描器实际看到的内容伸缩,而不是按整个注册表膨胀。
用户自定义上下文的注入:INFO.md 与 promptAppend
这是 08 号场景区别于其他样例的关键:它是唯一同时携带projectInfo(INFO.md)与promptAppend两个字段的场景(见 场景定义)。
注入位置:在框架要点与 Slug 笔记之后
在assemblePrompt中,两个用户自定义块被追加在所有框架生成内容之后:
// INFO.md 和 promptAppend 是用户撰写的,常自带 H1/H2, // 因此用水平分隔线(---)分隔,而不是再包一层我们自己的标题, // 避免出现两个相邻的 H2 之间什么都没有。 if (projectInfo && projectInfo.trim().length > 0) { sections.push(`---\n\n${projectInfo.trim()}`); } if (promptAppend && promptAppend.trim().length > 0) { sections.push(`---\n\n${promptAppend.trim()}`); }见 assemble.ts。整个组装顺序由注释明确给出:
[generic core] ## Threat highlights for this repo's tech stack ## Slug-specific reviewer notes [project INFO.md, verbatim] [config.json:promptAppend, verbatim]样例中两者的真实内容
- INFO.md(
## Project notes):指出认证辅助函数是lib/auth.ts里的requireUser(),内部路由集中在app/(internal)/**之下。这是给 Agent 的项目级背景知识——告诉它"认证长什么样、哪些目录是内部面",让它在研判时能区分真缺失与假缺失。 - promptAppend(
Custom: ...):追加"额外标记任何静默吞掉错误的 logger——这是本仓库已知的坑"。这是把仓库特有的历史教训沉淀成提示词的方式。
两者都以"原样追加(verbatim)"的方式进入 prompt,中间用---分隔。选择水平分隔线而非包装标题,是避免用户写的##标题与系统生成的##标题"双 H2 撞车"(assemble.ts 第 179-182 行注释,且测试明确断言最终 prompt 不含## Project context包装标题,见 prompt-assemble.test.ts)。
防重复发射:Agent 层只拿到空 projectInfo
生产链路中process()调用buildInvestigatePrompt时把projectInfo传成"",因为 INFO.md 已经躺在组装好的promptTemplate里了(shared.ts 第 394-398 行注释)。buildInvestigatePrompt只在调用方显式传入时才生成## Project Context块;模块化路径传空串,于是 INFO.md 在最终 prompt 中只出现一次。
测试用直接可验证的方式锁死了这一点:
it("INFO.md appears exactly once in the final prompt", () => { const sample = fullPromptFor(PROMPT_SAMPLE_SCENARIOS[7]); // 08-with-info-and-append const occurrences = sample.split("Auth helper is `requireUser()`").length - 1; expect(occurrences, "expected INFO.md content exactly once").toBe(1); });见 prompt-samples.test.ts。这条测试连同"样例必须与组装器+Agent 层输出逐字节一致"的断言(同文件第 66-91 行),共同保证了仓库里的样例文件永远不会与代码漂移——任何有意改变 prompt 形状的改动都要先跑UPDATE_PROMPT_SAMPLES=1 pnpm test:unit重写样本并人工 review diff。
Target Files:扫描候选如何落到 prompt 里
样例的## Target Files一节把批处理文件app/secrets.tsx连同扫描器的两条候选命中一起列出:
[xss] L22: dangerouslySetInnerHTML[secret-in-fallback] L4: process.env.X || "..."
这是buildInvestigatePrompt渲染的:对每个FileRecord,把候选匹配的 slug、行号、匹配模式拼成列表(shared.ts 第 368-385 行)。如果某文件没有任何扫描器命中,则会渲染成(no scanner hits — full holistic review),要求 Agent 对整文件做全面评审而非只盯候选行——保证process --diff之类场景下无命中的文件也不会被忽略。
输出规范:JSON findings 的契约
## Output Format一节(样例第 145-173 行)定义了模型必须返回的 JSON 结构:每个文件一个条目,findings数组中每条包含severity(CRITICAL/HIGH/MEDIUM/HIGH_BUG/BUG)、vulnSlug(可用已知类别,新颖问题用other-前缀)、title、description、lineNumbers、recommendation、confidence(high/medium/low)。无真实漏洞的文件也必须出现,带空findings数组。
这是整个管线的解析契约:模型输出先经 JSON 解析(严格解析失败会走jsonrepair容错),再逐条用findingSchema做字段级校验,校验失败的不落盘而是发起同会话的字段修复轮次(shared.ts 第 800-849 行parseInvestigateResults与第 857-895 行修复 prompt)。
如何在自己的项目里配置这两块上下文
方式一:deepsec.config.ts的项目声明字段
在项目声明的ProjectDeclaration上直接声明(见 configuration.md):
import { defineConfig } from "deepsec/config"; export default defineConfig({ projects: [ { id: "my-app", root: "../my-app", infoMarkdown: "## 仓库背景\n\n认证用 requireUser(),内部路由在 app/(internal)/**。", promptAppend: "额外标记任何静默吞掉错误的 logger——本仓库已知的坑。", }, ], });对应字段(packages/core/src/config.ts):
| 字段 | 类型 | 必填 | 作用 |
|---|---|---|---|
infoMarkdown | string | 否 | 注入到 AI 提示词中的仓库背景;与data/<id>/INFO.md同时存在时优先 |
promptAppend | string | 否 | 追加到该系统提示词末尾的自由文本 |
方式二:data/<id>/INFO.md与data/<id>/config.json
如果infoMarkdown未设置,deepsec 会读取data/<id>/INFO.md并注入其内容(适用于process、triage、revalidate)。docs/configuration.md对篇幅的建议是"几百词的仓库背景——代码库是干什么的、认证长什么样、威胁模型、已知误报来源",并说明 one-shot setup 会自动写入并校验该文件。
promptAppend等字段仍支持在data/<id>/config.json中声明(见 configuration.md):
{ "priorityPaths": ["app/api/", "lib/"], "promptAppend": "Pay extra attention to the booking flow.", "ignorePaths": ["**/legacy/**"] }如果配置文件与项目声明的同名字段同时存在,配置文件优先。一个真实可参考的样例在 samples/webapp/config.json,其中的promptAppend明确写了"跨租户访问(缺少 companyId 作用域)是本代码库影响最大的 bug 形态,检查数据库查询是否按req.session.user.companyId过滤"——这正是 08 号样例所展示的用法:把只有项目维护者知道的领域知识沉淀进提示词,引导 Agent 关注高价值 bug 形状。
处理器侧的数据流
从处理器入口看,projectConfig.promptAppend在初始化时被读入并透传(见 index.ts),最终经assemblePrompt({ projectInfo, promptAppend })进入组装器;组装器对两者一视同仁:非空白就追加,且都用---分隔保持与系统生成段落的分界。INFO.md 与 promptAppend 的"原样注入、只出现一次、位置固定"由此贯穿配置层 → 处理器 → 组装器 → Agent 层整条链路。
样例的生成与回归机制
prompt-samples/目录下的 11 份样例全部由 prompt-samples.test.ts 生成并持续校验:
- 常态运行:每个场景的
fullPromptFor()与磁盘上的.md文件逐字节比对,不一致即测试失败; - 有意变更时:
UPDATE_PROMPT_SAMPLES=1 pnpm test:unit会重写全部样例文件,然后通过 PR diff 审查变更内容。
这意味着08-with-info-and-append.md不只是文档,更是一份可回归的契约:任何对核心提示词、highlights、slug 笔记、INFO.md/promptAppend 注入位置或 Agent 层包装的改动,都会先在这里留下痕迹。测试还额外断言了两点:样例必须同时包含组装半区与 Agent 层文件列表两个部分(同文件第 93-100 行),以及 INFO.md 在最终 prompt 中恰好出现一次(第 102-106 行)——与样例头部注释声称的"确认它们不会被 Agent 层重复发射"完全对应。
小结
08-with-info-and-append是理解 deepsec 提示词工程的最小完备案例:一条组装器代码路径(assemblePrompt)加上一条 Agent 层包装路径(buildInvestigatePrompt),把通用核心、按需技术要点、按需 slug 笔记、用户自定义的 INFO.md 与 promptAppend、具体的候选文件列表与输出契约,拼成一份既不过度膨胀、又承载了项目特有知识的最终提示词。而样例文件本身被测试以字节级精度钉在仓库里,让 prompt 的每一次演化都变得可审查、可回放、可回归。若要进一步研究,可以从 assemble.ts、core.ts、slug-notes.ts 三个源文件入手,再对照 configuration.md 与 samples/webapp/config.json 把配置侧的字段接上。
- 应用安全
- 漏洞扫描
- 人工智能
- AI Agent
【免费下载链接】deepsec
Deepsec is a security harness for finding vulnerabilities in your codebase powered by coding agents
相关推荐
Deepsec 多语言仓库的 Python 批次提示词组装:语言过滤、按需注入与确定性样本机制全解析
Deepsec 多语言仓库的 Python 批次提示词组装:语言过滤、按需注入与确定性样本机制全解析 导读 本文基于 Deepsec 仓库中的确定性提示词样本
应用安全漏洞扫描人工智能AI AgentDeepsec 语言感知式安全审查提示词:多语言仓库中纯 TypeScript 批次的过滤组装机制
Deepsec 语言感知式安全审查提示词:多语言仓库中纯 TypeScript 批次的过滤组装机制 本指南以 prompt samples/05 polyglo
应用安全漏洞扫描人工智能AI AgentDeepsec 深入解析:Rails/Ruby 批量扫描的 Agent 调查提示词是如何构造与执行的
Deepsec 深入解析:Rails/Ruby 批量扫描的 Agent 调查提示词是如何构造与执行的 本篇以 Deepsec 仓库中的确定性提示词样例 prom
应用安全漏洞扫描人工智能AI Agent
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考