fix: block sensitive symlink targets
This commit is contained in:
@@ -101,6 +101,9 @@ func rejectSymlinkEscape(home string, candidate string) error {
|
||||
if !isInside(evaluatedHome, currentEvaluated) {
|
||||
return ErrOutsideCodexHome
|
||||
}
|
||||
if IsForbidden(currentEvaluated, evaluatedHome) {
|
||||
return ErrForbiddenPath
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package codexhome
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@@ -91,3 +92,22 @@ func TestResolveAgentTOMLRejectsUnsafeNames(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveAgentTOMLRejectsSymlinkToAuthJSON(t *testing.T) {
|
||||
home := filepath.Join(t.TempDir(), ".codex")
|
||||
agentsDir := filepath.Join(home, "agents")
|
||||
if err := os.MkdirAll(agentsDir, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(home, "auth.json"), []byte("{}"), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Symlink("../auth.json", filepath.Join(agentsDir, "demo.toml")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err := ResolveAgentTOML(home, "demo.toml")
|
||||
if !errors.Is(err, ErrForbiddenPath) {
|
||||
t.Fatalf("expected ErrForbiddenPath, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
| 2026-05-25 | 0 | review loop | 质量审查发现 docs/project.md 架构语气和 task_plan.md Phase 0 状态问题 | 已修复:改为目标架构语气,并将 Phase 0 标记为 complete |
|
||||
| 2026-05-25 | 1 | coding agent | 创建 Go 后端骨架和 Codex home 路径边界 | 已完成;未读取真实 `.codex` 数据文件 |
|
||||
| 2026-05-25 | 1 | review loop | 代码质量审查发现 symlink 绕过、敏感文件大小写、操作域 resolver、`CODEX_HOME` override 问题 | 已按 TDD 修复,并通过最终门禁 |
|
||||
| 2026-05-25 | 1 | review loop | 规格复审发现 `ResolveAgentTOML` 可经 `agents/demo.toml -> ../auth.json` symlink 绕过 forbidden 检查 | 已按 TDD 修复,并通过最终门禁 |
|
||||
|
||||
## Test Results
|
||||
|
||||
@@ -27,6 +28,11 @@
|
||||
| 2026-05-25 | `go test ./...` | PASS | 全量 Go 测试通过 |
|
||||
| 2026-05-25 | `git diff --check` | PASS | 无 whitespace error |
|
||||
| 2026-05-25 | `git status --short` | PASS | 仅本轮 Phase 1 修复文件变更 |
|
||||
| 2026-05-25 | `go test ./internal/codexhome` | FAIL | TDD 红灯:`agents/demo.toml -> ../auth.json` symlink 仍返回 nil |
|
||||
| 2026-05-25 | `go test ./internal/codexhome` | PASS | symlink final target 指向 root `auth.json` 时返回 forbidden error |
|
||||
| 2026-05-25 | `go test ./...` | PASS | 全量 Go 测试通过 |
|
||||
| 2026-05-25 | `git diff --check` | PASS | 无 whitespace error |
|
||||
| 2026-05-25 | `git status --short` | PASS | 仅本轮 Phase 1 symlink target 修复文件变更 |
|
||||
|
||||
## Bug Loop
|
||||
|
||||
@@ -36,3 +42,4 @@
|
||||
| 1 | `AUTH.JSON` 等大小写变体未被敏感文件 denylist 拦截 | 对敏感根文件相对路径做 case-insensitive 匹配 | `go test ./internal/codexhome` PASS |
|
||||
| 1 | 缺少操作域 resolver,通用 `ResolveInside` 容易误用 | 新增 `ResolveAgentTOML`,只允许 `agents/` 直属 `.toml` 文件名 | `go test ./internal/codexhome` PASS |
|
||||
| 1 | `docs/project.md` 记录 `CODEX_HOME` 但默认配置未读取 | `DefaultConfig` 增加 `CODEX_HOME` 非空 override | `go test ./internal/app` PASS |
|
||||
| 1 | `ResolveAgentTOML` 可通过 `agents/*.toml` symlink 指向 root `auth.json` 绕过 forbidden 检查 | 在 symlink 解析后对 evaluated final target 再执行 forbidden 检查 | `go test ./internal/codexhome` PASS |
|
||||
|
||||
@@ -30,3 +30,4 @@
|
||||
| Time | Phase | Error | Attempt | Resolution |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 2026-05-25 | 1 | 代码质量审查发现 symlink 边界绕过、敏感文件大小写匹配、缺少操作域 resolver、`CODEX_HOME` 未生效 | TDD 补充失败测试后修复 `codexhome` 和 `app` | 已通过最终验证 |
|
||||
| 2026-05-25 | 1 | 规格复审发现 `ResolveAgentTOML` 可通过 `agents/*.toml` symlink 指向 root `auth.json` 绕过 forbidden 检查 | TDD 补充 symlink-to-auth 测试后检查 resolved final target | 已通过最终验证 |
|
||||
|
||||
Reference in New Issue
Block a user