Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Potential fix for code scanning alert no. 154: Uncontrolled data used in path expression - #4207

Open
fiftin wants to merge 1 commit into
developfrom
alert-autofix-154
Open

Potential fix for code scanning alert no. 154: Uncontrolled data used in path expression#4207
fiftin wants to merge 1 commit into
developfrom
alert-autofix-154

Conversation

@fiftin

@fiftin fiftin commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

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, harden ChownDir(path string) by:

  • Resolving both the configured project tmp base (Config.TmpPath) and the input path to absolute cleaned paths.
  • Ensuring the target is either exactly the base or a child of the base using a prefix check with path separator boundary.
  • Returning an error when outside the allowed base.
  • Proceeding to os.Chown only 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

  • Bug Fixes
    • Improved protection for temporary-directory ownership changes by rejecting paths outside the configured temporary directory.
    • Paths are now normalized before validation to ensure consistent safety checks.

… in path expression

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
@fiftin
fiftin marked this pull request as ready for review September 8, 2026 11:03
Copilot AI lite review requested due to automatic review settings September 8, 2026 11:03
Comment thread util/config_sysproc.go
return fmt.Errorf("refusing to chown path outside tmp dir: %s", targetAbs)
}

return os.Chown(targetAbs, int(uid), int(gid))
@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 8c2556b2-b346-4465-a74f-877f7b88a704

📥 Commits

Reviewing files that changed from the base of the PR and between 3b339e5 and 4237272.

📒 Files selected for processing (1)
  • util/config_sysproc.go

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

ChownDir now resolves paths and restricts ownership changes to the configured temporary directory or its descendants.

Changes

Chown path validation

Layer / File(s) Summary
Path resolution and validation
util/config_sysproc.go
ChownDir resolves cleaned absolute paths, rejects targets outside the configured temporary directory, and applies os.Chown to the resolved target.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: 🟡 Moderate · up to 42372

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)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 1 files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the security fix and references the specific code scanning alert. It accurately matches the changes to validate paths before calling ChownDir.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch alert-autofix-154

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security review — PR #4207

Outcome: No medium, high, or critical vulnerabilities found in the added/modified code.

Scope reviewed

  • util/config_sysproc.go — new ChownDir path containment guard before os.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.

Open in Web View Automation 

Sent by Cursor Automation: Find vulnerabilities

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.TmpPath and the input path using filepath.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 chown when 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.

Comment thread util/config_sysproc.go
Comment on lines +88 to +103
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))
Comment thread util/config_sysproc.go
}

return os.Chown(path, int(uid), int(gid))
baseAbs, err := filepath.Abs(filepath.Clean(Config.TmpPath))

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread util/config_sysproc.go
}

baseWithSep := baseAbs + string(os.PathSeparator)
if targetAbs != baseAbs && !strings.HasPrefix(targetAbs, baseWithSep) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants