在 apply-changes 中进行路径遍历时,会将文件写入项目目录以外的位置(由模型控制的路径)
摘要: CVSS 向量: CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H (7.8 高) CWE: CWE-22 路径遍历 (任意文件写入) 详细信息 当 Plandex 执行计划的文件更改时,每个文件的目标路径来自模型的流式输出,并与项目根目录连接,没有包含性检查。包含父目录段的路径逃离了项目目录,因此内容包括具有遍历路径的文件的计划会将攻击者控制的内容写入主机上的任意位置。应用确认提示仅显示将应用的文件数量,并不显示或限制路径,而全自动 / `--auto-apply` 模式则完全不提示。通过调用真正的 `ApplyFiles` 函数进行了确认:一个文件被写入配置的项目根目录之外。 详细信息 目标在 `app/cli/lib/apply.go` 中构建: // ApplyFiles (~行 622), 对于每个文件: dstPath := filepath.Join(fs.ProjectRoot, path) ~行 638 ... os.MkdirAll(filepath.Dir(dstPath), 0755) ~行 679 (创建父目录) os.WriteFile(dstPath, []byte(content), 0644) ~行 687 `path` 来自模型流解析器 `app/server/model/plan/tell_stream_processor.go`,其中 `openingTagRegex` 截获 `<PlandexBlock ... path="(.+?)">`; `(.+?)` 截获接受 `../`。在源和 `os.WriteFile` 目标之间没有任何包含性检查 (grep 确认)。 `filepath.Join("/home/user/project", "../../../etc/cron.d/x")` 解析为 `/etc/cron.d/x`。由于 `os.MkdirAll` 创建中间目录,因此对于新路径也会成功写入。 信任边界是应用更改位于项目目录内。模型输出受到来自不受信任输入的影响(被毒化的仓库文件,攻击者控制的上下文加载到计划中,或间接提示注入),因此能够影响模型响应的攻击者可以将内容写入项目之外,例如写入 `~/.bashrc`、一个 shell 启动文件或 cron 文件,从而实现代码执行。 示例代码 <会根据请求分享> 影响 一个能够影响模型流式计划的攻击者(通过被毒化的仓库文件、攻击者控制的上下文或提示注入)将攻击者控制的内容写入开发人员机器上的任意路径,逃离项目目录。写入 shell 启动文件或 cron 文件会导致代码执行。应用确认不显示目标路径,而 `--auto-apply` / 全自动模式则不提示。 修复措施 计算 `dstPath = filepath.Join(ProjectRoot, path)` 后,强制执行包含性检查: `rel, err := filepath.Rel(ProjectRoot, dstPath); 如果 err != nil 或 rel == ".." 或 strings.HasPrefix(rel, ".."+string(os.PathSeparator)) 或 filepath.IsAbs(rel)`。在模型提供的 `path` 在解析时也拒绝绝对路径和 `..` 部分,并在应用确认中显示解析后的目标路径。 版本: …
内容来源: plandex-ai/plandex