SciFlow 定位为单用户、本地/私有部署的科研助手:SQLite 单文件、不建账号体系、不做多租户。它的主要威胁模型是「LLM 生成的代码 / 输入把本进程搞挂」,而不是「公网上的恶意多租户」。因此我们把安全预算花在:默认不暴露网络、沙箱资源上限、不存密钥、输入校验。
- 默认只监听回环地址:后端
main.ts默认HOST=127.0.0.1,不对局域网暴露零鉴权 API;确需对外暴露时必须显式HOST=0.0.0.0,并置于反向代理/内网之后。 - CORS 最小放行:默认仅
http://localhost:5173,多来源用逗号分隔,*需显式配置。 - 密钥不落盘、不入仓:API Key 仅从环境变量 / 本地
apps/server/.env读取;.env已在.gitignore,CI 会校验.env从未被跟踪;前端展示 Key 时做掩码处理。 - 实验沙箱隔离:实验执行通过隔离
spawn运行 Python,带SANDBOX_TIMEOUT_MS超时与独立工作目录;超时/失败时降级引导,不拖垮主进程。 - SQL 安全:全部 SQL 经 Drizzle ORM 参数化,禁止字符串拼接。
- 输入校验:全局
InputValidationPipe约束 JSON Body;MCP 工具参数按 JSON Schema 动态校验(缺参即拒),第三方工具返回统一加 untrusted-content 提示与指令隔离(对标 OWASP MCP Top 10)。 - 健壮性兜底:全局
unhandledRejection/uncaughtException兜底 + SQLitebusy_timeout+ SIGTERM/SIGINT 优雅关闭(WAL checkpoint 后退出)。 - mock 网关只听回环:
AI_MOCK=1的测试网关仅绑定127.0.0.1,零外网访问,仅供本机测试/演示。
核对命令(每次发版前必须重跑):
# 生产依赖(进入运行时/镜像的闭包)——目标 0 已知漏洞
pnpm audit --registry=https://registry.npmjs.org --prod
# 全量(含 devDependency;devDep 不进入发布产物)
pnpm audit --registry=https://registry.npmjs.org2026-10-15 依赖安全批次结果:全量告警 103 → 3,生产依赖 1 low(katex),其余 2 条为 devDependency 链路。
已完成的处置:
| 包 | 处置 | 验证 |
|---|---|---|
electron 38.8.6 → 41.10.7 |
关闭 5 条 high(沙箱继承、<webview> Node 集成、协议处理器、拖拽等) |
桌面打包成功 + prepare-server.mjs 按 Electron ABI 重编 better-sqlite3 |
simple-git → 4.0.2 / @simple-git/argv-parser → 2.0.1 |
关闭 2 critical + 3 high(命令注入/配置包含) | 构建 + 全量回归 161/0/0 通过 |
tar → 7.5.22(仅 7.5.x 受影响区间) |
关闭 1 critical + 多条 high/moderate | 构建 + 桌面打包通过 |
shell-quote → 1.12.0 |
关闭 1 critical | 脚本执行正常 |
vite → 6.4.3、vitest/@vitest/mocker → 4.1.11、tinypool |
关闭 critical/moderate(路径穿越、原型污染 RCE) | 单测 16+15 通过 |
js-yaml(仅 5.x 线 → 5.4.3)、source-map-js → 1.2.2、diff → 8.0.4、basic-ftp → 6.2.1、postcss-selector-parser → 7.1.6、semver(5.x 线) |
关闭 moderate/high/low | openapi:gen 通过(js-yaml v4 消费者保持 v4)、Tailwind typography CSS 正常、promptfoo 2/2 |
electron-builder → 26.15.3、app-builder-lib / builder-util-runtime |
关闭 high | 桌面 NSIS 打包成功 |
删除 pdf-parse(已被 unpdf 取代,零引用)、清理两份陈旧 package-lock.json |
消除错误锁文件与冗余依赖面 | pnpm install --frozen-lockfile 通过 |
无法消除的残留(3 条,均已核实无可用修复版):
| 包 | 严重度 | 公告要求 | 现状 | 引入路径 | 为何不影响发布产物 |
|---|---|---|---|---|---|
katex |
low | >=0.18.2 |
rehype-katex@7 / micromark-extension-math@3 固定 ^0.16.0,且 0.16 线最新发布就是 0.16.47 |
apps/web → rehype-katex / remark-math |
前端已声明 katex@^0.18.9(满足补丁);该传递副本仅被 markdown 数学语法解析链引用,属于转换期依赖,不直接渲染用户输入。风险面为原型污染绕过 trust 限制,需同时满足"上游已有原型污染"才有意义 |
node-forge |
high | >=1.4.1 |
npm 最新发布 1.4.0 | promptfoo(devDep) → jks-js → node-forge |
devDependency,不进生产依赖闭包、不进镜像;仅 eval 工具的证书解析 |
sprintf-js |
moderate | >=1.1.4 |
npm 最新发布 1.1.3 | electron(devDep) → @electron/get → global-agent → roarr |
devDependency,仅桌面打包期代理探测;不进入最终 app.asar 运行路径 |
另:extract-zip 的告警在 electron 41 中已由官方替代实现(@electron-internal/extract-zip)消解。
处置纪律:以上 3 条设置上游发版后立即重新钉版;pnpm-workspace.yaml 的 overrides 采用按受影响范围定点钉版(不做跨 major 全局替换——实测全局替换 js-yaml 会直接打坏 @redocly/openapi-core,使 openapi:gen 失败)。
- 依赖更新策略见
.github/dependabot.yml(每周检查;安全更新单独立组优先处理)。
- 不做登录态爬虫、不做邮箱授权守护进程——凡是编辑部/外部不会主动给你的数据,我们不假装自动获取。
- 不依赖任何国外在线学术源;网络出站仅指向你自己配置的 OpenAI 兼容端点。
如果你发现安全问题(例如可被利用的注入、沙箱逃逸、密钥泄露路径),请不要先发公开 Issue,优先私密披露:
- 通过仓库镜像(GitCode / Gitee / GitHub)的 Private Security Advisory / 私密 Issue 通道提交;
- 或邮件至维护者(占位:
sciflow-security@example.com,请以仓库主页最新联系方式为准)。
请附上:复现步骤、影响版本、环境(OS / Node / pnpm 版本)、PoC(如有)。我们会在 72 小时内 初步响应,确认后给出修复时间表并致谢。
提示:本工具无账号体系,请勿把它直接暴露到公网;任何公网部署都必须自行加网关鉴权与 TLS。