docs(sessions): record the renderer trust boundary for terminal launch

`launch_session_terminal` takes an arbitrary string from the renderer and
hands it to a shell. External audits report this as arbitrary command
execution over IPC. Document it as a known, accepted risk instead of
leaving it to be re-reported every audit cycle.

The precondition for exploiting it is control over the renderer, which
already implies local code execution as the user -- at which point going
through this command grants nothing extra. The renderer is treated as a
trusted boundary, supported by four facts each verified against the tree:

- the only `dangerouslySetInnerHTML` (ProviderIcon) takes an icon *name*,
  gated by `hasIcon()`, and reads the SVG from a build-time registry;
  neither users nor deep links can supply markup
- no `eval` / `new Function` anywhere in the frontend
- `frontendDist` points at the bundled output, the webview loads no
  remote origin, and there are no `<iframe>` / `<webview>` elements
- CSP is `script-src 'self'` -- no inline and no external scripts

The note lists what invalidates the conclusion, so the exemption is
falsifiable rather than a standing opinion: rendering network- or
config-sourced rich text, embedding a webview or navigating to a remote
origin, relaxing `script-src`, or introducing any way to execute
external code in the renderer. Any of those and this command must be
changed to accept a session identifier and rebuild the command in the
backend.

It also states explicitly that `cwd` is *not* covered. That value comes
from disk scanning and can legitimately contain `$(...)` regardless of
renderer trust, which is why it is escaped rather than exempted. Without
that sentence "the renderer is trusted" invites being read as "nothing
on this path needs handling".
This commit is contained in:
Jason
2026-07-28 22:47:18 +08:00
parent 35486afdda
commit 134bdc0e65
+34
View File
@@ -24,6 +24,40 @@ pub async fn get_session_messages(
.map_err(|e| format!("Failed to load session messages: {e}"))?
}
/// 在用户选定的终端里恢复一个会话。
///
/// # 安全边界:`command` 是刻意不加校验的
///
/// 本命令接受 renderer 传来的任意字符串并最终交给 shell。多份外部审计把这一点
/// 报成"IPC 任意命令执行",这里明确记录为**已知并接受的风险**,而不是待修缺陷。
///
/// 依据是本应用把 renderer 当作可信边界。支撑这一判断的是以下事实,全部逐条
/// 核实过(2026-07):
///
/// 1. 全库仅一处 `dangerouslySetInnerHTML``ProviderIcon.tsx`),其入参是图标
/// **名字**,经 `hasIcon()` 把关后从手工维护的构建期注册表取 SVG——用户与
/// 深链接都只能给名字,给不了标记内容
/// 2. 前端无 `eval` / `new Function`
/// 3. `tauri.conf.json` 的 `frontendDist` 指向打包产物,webview 不加载任何远程
/// 源;界面里也没有 `<iframe>` / `<webview>`
/// 4. CSP 为 `script-src 'self'`——既不允许内联脚本,也不允许外部脚本
///
/// 因此"攻击者能调用本 IPC"这一前提,成立时已意味着他能以当前用户身份执行代码;
/// 那种情况下绕道本命令并不会让他多拿到任何东西。
///
/// # 什么会推翻这个结论
///
/// 上面四条任意一条不再成立,本命令就必须改成**只接收 session / provider 标识、
/// 由后端从会话记录重建命令**。具体触发条件:
///
/// - 渲染任何来自网络或配置文件的富文本 / HTML / SVG 内容
/// - 引入 `<iframe>`、`<webview>`,或让 webview 导航到远程 origin
/// - 放宽 CSP 的 `script-src`(例如为了加载第三方脚本或统计 SDK)
/// - 引入任何在 renderer 内执行外部代码的机制
///
/// 相比之下 `cwd` 的处理**不属于**这条豁免:它是磁盘上扫来的项目路径,正常使用
/// 就可能含 `$(...)`,与 renderer 是否可信无关,因此在
/// `session_manager::terminal::shell_escape` 里做了完整的单引号转义。
#[tauri::command]
pub async fn launch_session_terminal(
command: String,