fix: validateDocmapPath — add EvalSymlinks to close directory-symlink bypass #150
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
validateDocmapPathincmd/review-bot/validatedocmap.gohas a directory-symlink bypass that contradicts its stated security invariant.Background
PR #142 added path-confinement hardening to prevent reading arbitrary host files via
--docmap. The hardening correctly:filepath.EvalSymlinkson--repo-rootto resolve itos.Lstatto reject file-level symlinksfilepath.Relfor confinement checkHowever,
os.Lstat(absPath)only avoids following the final component of the path. It does follow intermediate directory symlinks.Bypass
If a PR commits
.review-bot/as a directory symlink pointing outside the repo, and CI is configured with--docmap .review-bot/doc-map.yml:filepath.Abs("/.review-bot/doc-map.yml")→ textually inside repo ✅os.Lstat(absPath)follows the dir symlink, finds a regular file outside repo — no symlink bit on final component ✅filepath.Rel(resolvedRoot, absPath)passes because path is textually inside repo ✅This was verified with a reproducible Go test.
Fix
In
validateDocmapPath, afterfilepath.Abs, callfilepath.EvalSymlinksand use the resolved path for all subsequent checks:Note: after
EvalSymlinksthe path is already symlink-free, so theModeSymlinkcheck can be removed or kept as defense-in-depth (it will never fire, but the comment is still educational).Also add test
Severity
MINOR — requires the PR author to commit
.review-bot/as a directory symlink (aggressive modification) and relies on the CI-configured--docmappath landing on a parseable YAML outside the repo. Not easily exploitable in typical usage.Discovered during self-review of PR #142 (post-merge).