Potential fix for code scanning alert no. 154: Uncontrolled data used in path expression - #4207
Potential fix for code scanning alert no. 154: Uncontrolled data used in path expression#4207fiftin wants to merge 1 commit into
Conversation
… in path expression Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
| return fmt.Errorf("refusing to chown path outside tmp dir: %s", targetAbs) | ||
| } | ||
|
|
||
| return os.Chown(targetAbs, int(uid), int(gid)) |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (1)
Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review. 📝 WalkthroughWalkthrough
ChangesChown path validation
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: 🟡 Moderate · up to The change blocks direct path traversal, but a path beneath the temporary directory may still escape through symbolic links before ownership is changed. This should be addressed or explicitly accepted before merge. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Security review — PR #4207
Outcome: No medium, high, or critical vulnerabilities found in the added/modified code.
Scope reviewed
util/config_sysproc.go— newChownDirpath containment guard beforeos.Chown
Prior threads
No previous automation review threads on this PR.
Analysis summary
This PR remediates CodeQL alert #154 by refusing to chown paths outside Config.TmpPath. The check uses filepath.Clean + filepath.Abs and a prefix guard with a trailing path separator, which correctly blocks .. traversal and prefix-collision cases (e.g. /tmp/semaphore vs /tmp/semaphore_evil).
Attacker-controlled input trace: ChownDir is called from task execution (GetHomePath) and git clone (GetFullPath). For local repositories, GetFullPath can return an administrator-configured filesystem path via GitURL; before this change that could reach os.Chown unchecked. The new guard blocks that path unless it resolves under TmpPath.
Call-site alignment: Normal repository and home paths are constructed under GetProjectTmpDir (TmpPath/project_<id>), so legitimate chown operations remain allowed.
No new injection, authz bypass, or path-traversal sink was identified in the diff.
Sent by Cursor Automation: Find vulnerabilities
There was a problem hiding this comment.
🟡 Changes recommended
The current validation can be bypassed via symlink escape (since os.Chown follows symlinks) and the new security-sensitive logic lacks regression tests.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR aims to address code scanning alert #154 (“Uncontrolled data used in path expression”) by hardening util.ChownDir so it only performs os.Chown on paths that are within the configured temporary directory (Config.TmpPath).
Changes:
- Canonicalize
Config.TmpPathand the inputpathusingfilepath.Clean+filepath.Abs. - Enforce that the target path is either exactly the tmp base or a child of it (prefix + path-separator boundary).
- Return an error and refuse to
chownwhen the target is outside the tmp base.
File summaries
| File | Description |
|---|---|
| util/config_sysproc.go | Adds tmp-base path canonicalization and validation before performing os.Chown to mitigate path traversal/abuse. |
Review details
- Files reviewed: 1/1 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| baseAbs, err := filepath.Abs(filepath.Clean(Config.TmpPath)) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| targetAbs, err := filepath.Abs(filepath.Clean(path)) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| baseWithSep := baseAbs + string(os.PathSeparator) | ||
| if targetAbs != baseAbs && !strings.HasPrefix(targetAbs, baseWithSep) { | ||
| return fmt.Errorf("refusing to chown path outside tmp dir: %s", targetAbs) | ||
| } | ||
|
|
||
| return os.Chown(targetAbs, int(uid), int(gid)) |
| } | ||
|
|
||
| return os.Chown(path, int(uid), int(gid)) | ||
| baseAbs, err := filepath.Abs(filepath.Clean(Config.TmpPath)) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 42372728cd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } | ||
|
|
||
| baseWithSep := baseAbs + string(os.PathSeparator) | ||
| if targetAbs != baseAbs && !strings.HasPrefix(targetAbs, baseWithSep) { |
There was a problem hiding this comment.
Reject symlink escapes before chowning the target
When an attacker can pre-place an existing directory symlink below TmpPath—for example, in a writable or shared temporary tree—this lexical Abs/Clean check still accepts the link path. CmdGitClient.Clone calls MkdirAll before ChownDir, and MkdirAll succeeds for such a directory symlink; os.Chown then follows the link and can change ownership of a directory outside TmpPath while Semaphore is privileged. Use symlink-safe descriptor traversal with no-follow semantics rather than string containment. .claude/CLAUDE.mdL26-L28
Useful? React with 👍 / 👎.


Potential fix for https://github.com/semaphoreui/semaphore/security/code-scanning/154
General fix: before performing
os.Chown, canonicalize and validate the provided path against an expected safe base directory, and reject paths outside that base. This prevents traversal/absolute-path abuse even if upstream validation regresses.Best targeted fix here (without changing functionality): in
util/config_sysproc.go, hardenChownDir(path string)by:Config.TmpPath) and the inputpathto absolute cleaned paths.os.Chownonly after validation.This keeps existing behavior for legitimate repository temp dirs while blocking uncontrolled filesystem targets.
Suggested fixes powered by Copilot Autofix. Review carefully before merging.
Summary by CodeRabbit