问题
OMP 扩展读取 session 文件里的 current_task 后,直接执行 join(projectRoot, currentTask),没有验证解析后的目录是否仍在项目根目录或明确配置的受信任 Trellis 根目录内。
因此,一个形如 ../trellis-outside-task 的活动任务引用可以把 OMP 的 task 状态和文档读取到项目外。扩展随后会读取该目录的 task.json、prd.md 和 info.md,并将这些内容放进 trellis-task-context。
这不是远程攻击:修改本地 session 状态仍需要本地写权限。但扩展不应该把持久化指针当成可信路径,更不应该因此把另一个目录的任务文档送入模型上下文。
如何复现
-
在一个 Trellis OMP 项目中启动会话,使 .trellis/.runtime/sessions/ 中生成当前会话的 JSON 文件。
-
在项目旁边创建一个脱敏的任务目录:
mkdir -p ../trellis-outside-task
printf '{"title":"Outside task","status":"planning"}\n' \
> ../trellis-outside-task/task.json
printf 'OUTSIDE-PRD\n' > ../trellis-outside-task/prd.md
-
修改当前会话 JSON 的 current_task 为 ../trellis-outside-task。例如:
python3 - "$HOME/.path/to/current-session.json" <<'PY'
import json
import sys
from pathlib import Path
path = Path(sys.argv[1])
data = json.loads(path.read_text())
data['current_task'] = '../trellis-outside-task'
path.write_text(json.dumps(data))
PY
-
重新触发 OMP 的 session start,或重新打开该会话。
-
检查 trellis-task-context 或当前任务状态。
实际结果
当前 OMP 扩展把项目外目录识别为 active task,并读取其中的 task.json 和 prd.md。在上述复现中,任务上下文会出现 OUTSIDE-PRD,而该文件不在项目目录内。
同样的问题也适用于通过软链接逃逸的任务目录。项目内合法的 .trellis/tasks/... 引用则可以正常工作。
期望结果
OMP 应该通过统一的 task resolver 处理 active-task 引用:
- 先规范化引用并解析真实路径;
- 只允许项目根目录内的 task,或
.trellis/config.yaml 明确声明的受信任 Trellis 根目录;
- 验证目标是目录,并且包含合法的
task.json;
.. 越界、绝对路径、软链接逃逸或缺失目标都回退为 no_task;
- OMP dogfood copy 和 CLI 打包模板使用同一套边界检查。
当前 main 中的代码路径
main @ c8e327a99d8ae7bfcb67523ab89b0ca8c721e63a 中,active task 仍然直接拼接路径:
|
const currentTask = sessionData.current_task; |
|
if (typeof currentTask !== "string" || !currentTask) |
|
return { status: "no_task", taskDir: null, taskTitle: null }; |
|
|
|
const taskDir = join(projectRoot, currentTask); |
|
const taskJsonPath = join(taskDir, "task.json"); |
|
if (!existsSync(taskJsonPath)) return { status: "no_task", taskDir: null, taskTitle: null }; |
|
|
|
let taskData: Record<string, unknown>; |
|
try { |
|
taskData = JSON.parse(readFileSync(taskJsonPath, "utf-8")); |
|
} catch { |
|
return { status: "no_task", taskDir: null, taskTitle: null }; |
|
} |
|
|
|
return { |
|
status: typeof taskData.status === "string" ? taskData.status : "planning", |
|
taskDir, |
|
taskTitle: typeof taskData.title === "string" ? taskData.title : null, |
- dogfood copy:
|
const currentTask = sessionData.current_task; |
|
if (typeof currentTask !== "string" || !currentTask) |
|
return { status: "no_task", taskDir: null, taskTitle: null }; |
|
|
|
const taskDir = join(projectRoot, currentTask); |
|
const taskJsonPath = join(taskDir, "task.json"); |
|
if (!existsSync(taskJsonPath)) return { status: "no_task", taskDir: null, taskTitle: null }; |
|
|
|
let taskData: Record<string, unknown>; |
|
try { |
|
taskData = JSON.parse(readFileSync(taskJsonPath, "utf-8")); |
|
} catch { |
|
return { status: "no_task", taskDir: null, taskTitle: null }; |
|
} |
|
|
|
return { |
|
status: typeof taskData.status === "string" ? taskData.status : "planning", |
|
taskDir, |
|
taskTitle: typeof taskData.title === "string" ? taskData.title : null, |
|
}; |
#534 和 PR #534 加固的是 Python CLI 的 task resolver,但没有修改 OMP extension 的这条直接读取路径,因此仍然可以在 OMP 中复现。
环境
- Trellis:
main @ c8e327a
- OMP:
17.2.12
- Node.js:
v24.10.0
- macOS:
26.5.2
问题
OMP 扩展读取 session 文件里的
current_task后,直接执行join(projectRoot, currentTask),没有验证解析后的目录是否仍在项目根目录或明确配置的受信任 Trellis 根目录内。因此,一个形如
../trellis-outside-task的活动任务引用可以把 OMP 的 task 状态和文档读取到项目外。扩展随后会读取该目录的task.json、prd.md和info.md,并将这些内容放进trellis-task-context。这不是远程攻击:修改本地 session 状态仍需要本地写权限。但扩展不应该把持久化指针当成可信路径,更不应该因此把另一个目录的任务文档送入模型上下文。
如何复现
在一个 Trellis OMP 项目中启动会话,使
.trellis/.runtime/sessions/中生成当前会话的 JSON 文件。在项目旁边创建一个脱敏的任务目录:
修改当前会话 JSON 的
current_task为../trellis-outside-task。例如:重新触发 OMP 的 session start,或重新打开该会话。
检查
trellis-task-context或当前任务状态。实际结果
当前 OMP 扩展把项目外目录识别为 active task,并读取其中的
task.json和prd.md。在上述复现中,任务上下文会出现OUTSIDE-PRD,而该文件不在项目目录内。同样的问题也适用于通过软链接逃逸的任务目录。项目内合法的
.trellis/tasks/...引用则可以正常工作。期望结果
OMP 应该通过统一的 task resolver 处理 active-task 引用:
.trellis/config.yaml明确声明的受信任 Trellis 根目录;task.json;..越界、绝对路径、软链接逃逸或缺失目标都回退为no_task;当前 main 中的代码路径
main @ c8e327a99d8ae7bfcb67523ab89b0ca8c721e63a中,active task 仍然直接拼接路径:Trellis/packages/cli/src/templates/omp/extensions/trellis/index.ts.txt
Lines 222 to 240 in c8e327a
Trellis/.omp/extensions/trellis/index.ts
Lines 115 to 134 in c8e327a
#534 和 PR #534 加固的是 Python CLI 的 task resolver,但没有修改 OMP extension 的这条直接读取路径,因此仍然可以在 OMP 中复现。
环境
main @ c8e327a17.2.12v24.10.026.5.2