Go Path Traversal Vulnerability Patterns (CWE-22/59)
当审计 Go 代码中涉及文件路径操作、归档解压、符号链接处理、容器卷挂载时加载此 Skill。
Detection Strategy
Sources(攻击入口):
- HTTP 请求参数中的文件名/路径(
r.URL.Query().Get("file")) - Archive 条目路径(
tar.Header.Name,zip.File.Name) - Git 仓库中的文件路径(go-git clone/checkout)
- gRPC 请求中的文件路径字段
- Helm chart 中的文件引用
- 用户上传的文件名(
multipart.FileHeader.Filename)
Sinks(危险操作):
os.Open(path),os.Create(path),os.ReadFile(path)os.WriteFile(path, data, perm)filepath.Join(base, userInput)-- 当 userInput 为绝对路径时覆盖 baseos.Symlink(target, link),os.Readlink(path)http.ServeFile(w, r, path),http.FileServer(http.Dir(root))io.Copy写入用户控制的路径- Container runtime 的 volume mount 路径解析
Sanitization(路径安全屏障):
filepath.Clean(path)-- 规范化路径但不防止绝对路径filepath.Rel(base, target)-- 计算相对路径,返回..开头则越界strings.HasPrefix(filepath.Clean(path), base)-- Clean 后前缀检查filepath.EvalSymlinks(path)-- 解析所有符号链接后再检查securejoin.SecureJoin(base, path)--filepath-securejoin库
检测路径:
# filepath.Join 与用户输入
grep -rn "filepath.Join" --include="*.go"
# 文件操作
grep -rn "os.Open\|os.Create\|os.ReadFile\|os.WriteFile\|os.MkdirAll" --include="*.go"
# Archive 解压
grep -rn "tar.NewReader\|zip.OpenReader\|archive/tar\|archive/zip" --include="*.go"
# Symlink 操作
grep -rn "os.Symlink\|os.Readlink\|os.Lstat\|filepath.EvalSymlinks" --include="*.go"
# HTTP 文件服务
grep -rn "http.ServeFile\|http.FileServer\|http.Dir" --include="*.go"
# 路径安全检查
grep -rn "filepath.Clean\|filepath.Rel\|securejoin\|SecureJoin" --include="*.go"
- 定位文件操作的 Sink 函数(
os.Open,os.Create,http.ServeFile等) - 回溯路径参数的来源,确认是否包含用户输入
- 验证路径是否经过安全检查:
filepath.Join(base, input)是否考虑了 input 为绝对路径的情况?- Archive 解压是否检查了条目路径包含
..或绝对路径? - 是否先
filepath.EvalSymlinks再做路径检查(防止 symlink TOCTOU)? http.FileServer的 root 目录是否限制了访问范围?
- 若无安全检查或检查可被绕过 -> 标记为候选漏洞
Detection Checklist
-
filepath.Join绝对路径覆盖审计 (CWE-22):filepath.Join("/safe/base", userInput)当userInput = "/etc/passwd"时,结果为/etc/passwd而非/safe/base/etc/passwd。必须在 Join 后检查结果是否仍在 base 目录下。 - Archive 解压路径审计 (CWE-22):
tar.NewReader/zip.OpenReader解压时,是否检查header.Name不包含..且不是绝对路径?是否使用filepath.Clean后再验证前缀? - Symlink TOCTOU 审计 (CWE-59):是否先
os.Lstat检查文件类型,然后os.Open读取?攻击者可在检查后、读取前将文件替换为 symlink。应使用filepath.EvalSymlinks或O_NOFOLLOW。 - Container Volume Mount 路径逃逸审计 (CWE-22):容器 runtime 是否正确解析 volume mount 路径中的 symlink?Pterodactyl Wings 风格的 mount path 是否在 container namespace 内解析?
-
http.ServeFile/http.FileServer审计 (CWE-22):路径参数是否来自用户输入?http.Dir是否限制在预期目录?是否处理了../编码变体(%2e%2e%2f)? - Git Clone/Checkout 路径审计 (CWE-22):go-git 的
worktree.Checkout是否验证文件路径?恶意 Git 仓库是否能通过精心构造的 tree object 写入任意位置? - Helm Chart Symlink 审计 (CWE-59):Helm chart 包中的 symlink 是否指向 chart 目录外部?
helm install是否跟随了恶意 symlink? -
filepath.EvalSymlinks使用时机审计 (CWE-59):路径安全检查是否在EvalSymlinks之后执行?先检查再 Eval 可能被 symlink 绕过。
False Positive Exclusion Guide
以下模式不是此类漏洞:
filepath.Join用于拼接硬编码路径 -- 如filepath.Join(configDir, "settings.yaml"),无用户输入http.FileServer仅服务静态资源目录 -- 且路径参数不可被用户控制os.ReadFile读取配置文件 -- 路径来自环境变量或命令行参数(非 HTTP 输入)- 测试代码中的临时目录操作 --
t.TempDir()中的文件操作
以下模式需要深入检查:
filepath.Clean后直接使用 --Clean不防止绝对路径,需要额外的前缀检查strings.Contains(path, "..")作为唯一检查 -- 可被....//等变体绕过- Lstat + Open 分开调用 -- 存在 TOCTOU 窗口
io.Copy目标路径来自 archive header -- Zip Slip 经典模式
Real-World Cases
详见 references/cases.md(7 个真实案例,需要时加载)。