# 安全策略 / SECURITY Project Compass(项目罗盘)是一个**会读取你代码的开发工具**。这个定位本身就有隐私含义, 所以本文件先说清边界,再说怎么报告漏洞。 - [隐私边界(必读)](#隐私边界必读) - [威胁模型](#威胁模型) - [设计上不提供的绕过开关](#设计上不提供的绕过开关) - [支持的版本](#支持的版本) - [如何报告安全问题](#如何报告安全问题) - [我们会怎么处理](#我们会怎么处理) - [给使用者的建议](#给使用者的建议) --- ## 隐私边界(必读) ### 插件会读什么 | 会读 | 说明 | | --- | --- | | 项目内的源码与配置文件 | 目录遍历、读取文本内容用于解析(这是产品的核心功能) | | 清单文件 | `package.json` / `pyproject.toml` / `go.mod` / `pom.xml` / `Cargo.toml` 等,用于识别技术栈与命令 | | 文档与 CI 配置 | 用于画像与「跑起来需要什么」 | | 文件元信息 | 体积、行数、修改时间等 | ### 插件不会读什么 **命中敏感规则的路径只做 `stat`,内容永不读取。** | 不读 | 例子 | | --- | --- | | 环境变量文件 | `.env`、`.env.*`、`*.local`、`config/local.*` | | 私钥与证书 | `*.pem`、`*.key`、`*.p12`、`*.pfx`、`id_rsa*`、`id_ed25519*` | | 凭据文件 | `credentials*`、`secrets*`、`service-account*.json`、`.npmrc`、`.netrc`、`.git-credentials` | | 云与部署凭据 | `.aws/credentials`、`.gcloud/**`、`kubeconfig*`、`.docker/config.json` | | 密钥库与状态文件 | `*.jks`、`*.keystore`、`terraform.tfstate*`、`*.tfvars` | | 数据库与抓包文件 | `*.sqlite`、`*.sqlite3`、`*.db`、`*.pcap` | 完整默认清单见 [CONFIG.md 的敏感文件默认清单](docs/CONFIG.md#敏感文件默认清单)。 命中时只记录**路径、类型与命中原因**,用于在报告里提示「这个文件存在且敏感,注意别提交」。 **值、内容、片段都不会进入内存、缓存、索引或报告。** `scan.json` 里的 `signals.secretSuspects` 记录的是**位置与疑似类型**(例如某行的"高熵字符串"), 同样不含值。 ### 插件会写什么 只写**被分析项目内**的两个目录: | 目录 | 内容 | | --- | --- | | `<项目>/.project-compass/` | 机器状态:扫描快照、IR、解析缓存、检索索引、运行状态、问答留痕 | | `<项目>/docs/project-compass/`(可配置 `outputDir`) | 人类产物:6 份报告 | **不改动任何业务代码**,不修改 `package.json`,不安装依赖,不执行项目里的任何命令 (`scan` 只**报告**发现了哪些命令,从不运行它们)。 ### 网络 | 场景 | 行为 | | --- | --- | | 默认(`llm.enabled: false`) | **零网络请求**。扫描、解析、建索引、检索、问答全部在本机完成 | | 显式开启 LLM(`llm.enabled: true` + 调用方传 `withLlm`) | 会把生成叙事所需的**最小代码上下文**发送给配置的 provider | | 遥测 / 使用统计 / 崩溃上报 | **不存在**。本插件没有任何回传通道 | **在受监管环境里的建议**:保持 `llm.enabled: false`。此时不存在任何数据出境路径。 ### LLM 开启后的额外保护 即使显式打开了 LLM,仍有一层结构性保护:**所有 LLM 输出必须通过验证器**。 验证器会检查输出中提到的每个路径是否存在于 IR、每个行号是否落在该文件的 `1..loc` 内、 每个符号名是否能在 IR 中找到。 - 验证不通过的声明**一律丢弃**,`validation.dropped` 给出丢弃条数; - 报告里写明丢弃了多少条; - `maxCalls` / `maxTokens` 是硬上限,防止意外的调用放大。 这条机制的设计意图是防止「模型幻觉变成报告里的事实」。它**不**防止「模型看到了你的代码」 ——那是 LLM 开关本身的语义,请据此评估。 --- ## 威胁模型 我们按以下模型评估安全问题。**不在模型内的风险会明确说明**。 ### 在模型内(我们会当作安全问题处理) | 风险 | 期望的行为 | | --- | --- | | **敏感文件内容泄漏** | 命中敏感规则的路径,其内容出现在任何产物(报告、JSON、缓存、索引、日志、工具返回、错误信息)里——**这是最高级别的安全问题** | | **意外网络请求** | 在默认配置下观察到任何出站网络流量 | | **写入越界** | 写入了 `<项目>/.project-compass/` 与 `outputDir` 之外的路径 | | **命令执行** | 任何形式的命令执行(`spawn` / `exec` / `eval` / 动态 `import` 用户代码) | | **路径穿越** | 通过构造路径(`../`、绝对路径、符号链接)读到或写到项目范围之外 | | **拒绝服务** | 单个畸形文件或恶意构造的仓库导致进程崩溃、内存耗尽或无界循环(预算机制失效) | | **绕过隐私边界** | 通过配置(`include`、`sensitive.extraPatterns`、`outputDir`)使敏感文件内容被读取或落盘 | ### 在模型外(我们会尽力,但不承诺) | 风险 | 说明 | | --- | --- | | **你主动开启 LLM 后的数据出境** | 这是该开关的既定语义。选择 provider 与数据条款是你的责任 | | **恶意代码本身的分析结果** | 本插件只做静态解析,**不执行**被分析项目里的任何代码。但如果项目里存在恶意文件,插件的解析器会读到它(读源码是产品功能),解析器按"不抛错"原则处理内容,不会执行它 | | **你本机的其他进程** | 插件不提供加密、不做进程隔离。它能读的文件取决于运行它的用户权限 | | **供应链** | 本插件零外部依赖,因此不存在来自本插件的供应链风险。但它运行在 DSH 宿主与 Node 运行时之上,那两层的安全问题不在本插件的范围内 | | **产物文件的访问控制** | 写出的报告就是普通文件,权限由你的系统决定。若报告目录会被提交或共享,请自行确认内容适合共享(默认 LLM 关闭时,报告内容全部来自你项目里**非敏感**的源码) | ### 明确的安全假设 1. **宿主的沙箱/权限是有效的**——本插件不自行实现沙箱; 2. **被分析项目的源码可以进入内存**——这是产品功能的前提; 3. **敏感判定的清单是保守的**——宁可把「像密钥的东西」登记为敏感而不读,代价是可能漏掉一些 本该被分析的文件(这是有意的取舍,可通过重命名解决,而不是通过放开边界); 4. **用户配置是可信的**——但我们仍然**不允许配置绕过隐私红线**(见下)。 --- ## 设计上不提供的绕过开关 这些**不是**"还没做",而是有意不提供: | 不提供 | 原因 | | --- | --- | | 「强制读取敏感文件」的配置项 | 隐私红线不通过配置开关决定。需要分析某个被误判的文件,请重命名它 | | 「执行项目命令」的能力 | 本插件是读取与说明工具。命令发现只报告,不执行 | | 「禁止写入的状态目录开关」 | 状态目录是插件自己的派生数据区;它被默认忽略,且可随时删除 | | 任何遥测开关 | 因为没有遥测。不存在"关掉的遥测" | | 默认联网的选项 | 默认必须零网络。网络能力只能显式开启,且要能被审计 | --- ## 支持的版本 安全修复只针对**最新发布版本**。本插件目前处于 `0.x` 阶段: | 版本 | 支持 | | --- | --- | | 最新 `0.x` | ✅ 接受安全报告并修复 | | 更早的 `0.x` | ❌ 请先升级到最新版本 | | `1.0` 之后 | 将按最新的两个 minor 版本提供安全修复(届时更新本表) | Node.js:≥ 20.11(与 `package.json` 的 `engines` 一致)。更老的运行时不受支持。 --- ## 如何报告安全问题 **请不要用公开 issue 报告安全问题。** 请通过以下**私密渠道**之一: 1. **GitHub Private vulnerability reporting**(推荐)—— 仓库的 **Security** 标签页 → **Report a vulnerability**; 2. 如果该入口不可用,请**先通过一个不包含细节的公开 issue 请求建立私密联系渠道** (只说"我有一个安全问题想私下报告"),维护者会回复私密联系方式。 **请包含** | 项 | 说明 | | --- | --- | | 受影响的版本 | 例如 `0.1.0`,以及 Node 版本 | | 问题类别 | 敏感内容泄漏 / 意外网络 / 越界写入 / 路径穿越 / 命令执行 / DoS / 边界绕过 | | 复现步骤 | 最小可复现:一个目录结构 + 需要的配置 + 执行的命令 | | 观察到的行为 | 实际发生了什么,最好附产物片段(**请先脱敏**) | | 期望的行为 | 你认为应该怎样 | | 影响评估 | 攻击者能拿到什么、需要什么前提 | **请不要**在报告里附上真实的密钥、令牌或生产数据——用等价的最小样例即可。 **响应时间**(尽力而为,非法律承诺): | 阶段 | 目标 | | --- | --- | | 确认收到 | 3 个工作日内 | | 初步判定(是否在模型内、严重级别) | 7 个工作日内 | | 修复或缓解方案 | 视严重级别,尽力在 30 天内 | | 公开披露 | 修复发布后,与报告者协商 | **我们不会** - 对善意报告采取法律行动; - 要求你签署保密协议才能报告; - 在未与你协商的情况下公开你的身份。 如果你希望被致谢,请在报告中说明署名方式;不想被提及也完全没问题。 --- ## 我们会怎么处理 1. **确认与分级**——判断是否落在威胁模型内,评估影响面(是否涉及敏感内容出逃); 2. **复现**——用最小可复现样例在本地验证; 3. **修复**——优先选择"结构上不可能发生"的修法(例如把读取路径收紧到唯一一处), 而不是在调用点逐个加判断; 4. **补测试**——为安全修复补一个回归测试,确保同类问题不会再回来; 5. **发布**——在 [CHANGELOG.md](CHANGELOG.md) 的 `Security` 小节说明影响范围与修复版本 (在报告者同意的前提下披露细节); 6. **致谢**——按报告者的意愿致谢。 --- ## 给使用者的建议 | 建议 | 理由 | | --- | --- | | 保持 `llm.enabled: false`(默认) | 此时不存在数据出境路径 | | 确认 `.project-compass/` 在你的忽略规则里 | 默认已忽略;请勿把它提交进版本库 | | 决定 `docs/project-compass/` 是否进版本库 | 它是给人看的产物,可能包含模块名与代码片段。默认**不**忽略它,请按团队规范决定是否提交 | | 在陌生/不可信仓库上先小范围试 | 用 `projectPath` 指向一个子目录,或先用 `ignore` 排除不需要的部分 | | 把敏感文件放在默认清单之外时,用 `sensitive.extraPatterns` 追加 | 追加是安全的(只登记不读);**不存在**"取消敏感"的开关 | | 定期清理 `.project-compass/` | 它是派生数据,删除只会让下次分析变慢 | 如果你是安全研究员,欢迎针对「敏感内容是否真的出不去」这条边界做对抗性测试—— 这是本插件最核心的隐私承诺。