报告漏洞
请通过 GitHub 的私密漏洞报告(private vulnerability reporting)提交,本仓库已开启该功能:报告漏洞
新建一份私密安全公告草稿,只有你和维护者可见。
仓库目前没有
SECURITY.md,也没有承诺的响应时间或受支持版本策略。修复随常规版本发布。安全模型
修改下面这些部分时,要保持这些性质不变,评审时会检查。项目信任与受限模式
打开一个项目文件夹,就可能运行由项目控制的代码:会执行构建脚本的语言服务器、运行配置、构建工具、git 钩子、项目插件。所以执行类操作需要用户信任。- 打开一个尚未做过决定的项目时,会弹出 信任并打开项目? 对话框,提供 信任项目、以受限模式预览 和 不打开。已有决定和受信任的位置在设置的 项目信任 页面(安全 分组)里管理,撤销信任 是一个 action。
- 信任是用户自己的状态(
crates/ide-host/src/trust.rs)。项目设置永远不能授予信任。 - 拦截在后端而不是 UI:每个 IPC 命令执行前,都要在 Tauri 的 invoke handler(
src-tauri/src/lib.rs)里经过Host::authorize_command。未受信任的项目里,只有显式白名单(restricted_command_allowed)中的命令能运行:读写文件和文档、语法、搜索、导航、本地历史、拼写、分析、重构、设置等。 - 这份白名单是默认拒绝的:新增的任何会执行东西的命令,在你有意识地把它归类之前,受限模式下一律拒绝。 不要为了让某个功能在受限模式下“能用”就把执行类命令加进白名单。
- 在命令层之下,项目受信任之前语言服务器不会启动(
LspManager的执行开关),git 以禁止执行的方式运行,也不使用项目里配置的git可执行文件。项目插件(.openidea/plugins/)只在受信任的项目中加载。 - 远程窗口中,桌面端在转发命令前会先确认远程项目是否受信任,
openidea-server对每个invoke还会再校验一次。
crates/ide-host/tests/trust.rs、trust_git_binary.rs。
插件沙箱
插件是由 wasmtime 运行的 WebAssembly 组件(crates/ide-plugin),内部实现见插件宿主。
- 每个插件有自己的
Store:没有预打开的目录、没有环境变量、没有网络、不继承标准输入输出,只有 WASI 的时钟和随机数,加上宿主函数。 - 凡是涉及文件、进程、网络、VCS 写入等的宿主函数,都受
plugin.toml中声明的 capability 约束,由用户在安装时(或更新要求更多权限时)授予。每个 capability 都有风险等级,在授权对话框里展示。未授予时调用返回denied,插件继续运行。 process:<program>授权会固定程序的绝对路径和内容哈希,文件被替换后要重新批准才能运行。fs.read:/fs.write:路径在比较前解析成真实路径,软链接无法越过授权范围。- 每次调用都受 fuel、墙钟时限和内存上限约束。trap 只会丢弃该实例,不会拖垮 IDE。
- 插件 Web 视图运行在沙箱 frame 中:不透明源、无网络、除 frame bridge 外没有 IDE API;文件带严格的 CSP 返回。
- 插件包使用 Ed25519 签名。市场索引是发布者的信任根,并携带吊销信息;已安装插件只会静默更新到同一密钥(或它背书过的密钥)签名的包。
本地服务
- MCP 服务(
crates/ide-mcp):监听127.0.0.1的随机端口,要求每次运行随机生成的 bearer token,Origin或Host不匹配的请求一律拒绝(防 DNS rebinding)。 - 内置 Web 服务(
crates/ide-web):在127.0.0.1上只读提供项目文件;每个 URL 都以每次运行随机生成的 token 开头,Host不对的请求会被拒绝。 - Tauri MCP bridge(
tauri-plugin-mcp-bridge):只编译进 debug 构建,绑定127.0.0.1。
远程开发与子进程
openidea-server通过 SSH、wsl.exe --exec或docker exec启动。WSL 和 dev container 两种方式把所有变量值(路径、版本、id)作为独立参数传递,只有固定脚本才会交给sh -c。请保持这一点:永远不要把值拼进 shell 字符串。- 远程插件用到的密钥留在桌面端的钥匙串里,服务端在请求需要时才向桌面端索取。
依赖
每次 Rust 改动,CI 都会运行cargo deny check(deny.toml):安全公告、许可证、禁用的 crate 和允许的来源。