Skip to content

main: keep working-directory resolution inside GITHUB_WORKSPACE - #620

Open
anupamme wants to merge 2 commits into
arnested:mainfrom
anupamme:fix-repo-go-version-action-working-directory-path-traversal
Open

anupamme wants to merge 2 commits into
arnested:mainfrom
anupamme:fix-repo-go-version-action-working-directory-path-traversal

Conversation

@anupamme

@anupamme anupamme commented Sep 1, 2026

Copy link
Copy Markdown

Summary

Validate that working-directory resolves to a path inside GITHUB_WORKSPACE before reading go.mod, including symlink-based escapes.

Motivation

working-directory is meant to select the project directory the action inspects. Currently, values like ../../etc or a symlink pointing outside the workspace are silently accepted, causing the action to read an unrelated go.mod elsewhere on the runner. This isn't a meaningful privilege boundary on its own (a workflow author who controls working-directory already controls the workflow), but it is surprising, unintended behavior relative to what the input is documented to do.

Changes

  • src/main.js: extracted validateWorkingDirectory(), which resolves working-directory against GITHUB_WORKSPACE, rejects paths that escape it (including via fs.realpathSync symlink resolution), and lets a genuinely missing directory fall through to the existing gomod() error.
  • __tests__/main.test.js: added regression tests for path traversal, absolute paths outside the workspace, valid directories, and symlink escapes.

Note

This PR originally described the change as a "HIGH severity security" fix (from an automated scanner report). Per discussion below, that framing overstated the impact — this is now presented as a defensive input-validation / correctness improvement, not a critical vulnerability fix.

Automated security fix generated by OrbisAI Security

Signed-off-by: anupamme <mediratta@gmail.com>
@CLAassistant

CLAassistant commented Sep 1, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Copilot AI 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.

🟡 Changes recommended

The new workspace-boundary check can still be bypassed via symlinks/junctions within the workspace and needs additional hardening and regression coverage before it reliably addresses the reported vulnerability.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR hardens the GitHub Action’s handling of the working-directory input to mitigate a path traversal risk when reading go.mod, aligning with the stated goal of fixing a high-severity security issue in src/main.js.

Changes:

  • Added path-based normalization and an “inside workspace” check for working-directory before reading go.mod.
  • Switched from string concatenation to path.join() when constructing the go.mod path.
File summaries
File Description
src/main.js Resolves and validates working-directory against the workspace before reading go.mod.
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 src/main.js Outdated
Comment on lines +29 to +33
if (
resolvedDirectory !== workspace &&
!resolvedDirectory.startsWith(workspace + path.sep)
) {
throw new Error('working-directory must resolve to a path inside the workspace')
Comment thread src/main.js
Comment on lines +27 to +35
const workspace = path.resolve(process.env.GITHUB_WORKSPACE || process.cwd())
const resolvedDirectory = path.resolve(workspace, workingDirectory)
if (
resolvedDirectory !== workspace &&
!resolvedDirectory.startsWith(workspace + path.sep)
) {
throw new Error('working-directory must resolve to a path inside the workspace')
}
const content = gomod(path.join(resolvedDirectory, 'go.mod'))
@anupamme

anupamme commented Sep 2, 2026

Copy link
Copy Markdown
Author

Review Feedback Addressed

I've automatically addressed 1 review comment(s):

The reviewer flagged that there are no regression tests for the new workspace-boundary validation and that the current path.resolve + startsWith check does not catch symlink-based escapes.

Changes made:

  1. src/main.jsfs is imported; the validation logic is extracted into an exported validateWorkingDirectory() function that (a) keeps the existing string-based traversal check and (b) adds fs.realpathSync calls to reject symlinks that point outside the workspace. realpathSync ENOENT errors are swallowed so that a legitimately missing directory still falls through to the existing gomod() error. The top-level run() call is guarded by process.env.NODE_ENV !== 'test' so the file can be imported in tests without executing the action.
  2. __tests__/main.test.js – A new describe('validateWorkingDirectory', ...) block is appended with four tests: rejects ../.., rejects an absolute path outside the workspace, accepts an empty string (workspace root), accepts a valid subdirectory, and rejects a real symlink that points outside the workspace.

Files modified:

  • src/main.js
  • __tests__/main.test.js

The changes have been pushed to this PR branch. Please review!

@pull-request-size pull-request-size Bot added size/M and removed size/S labels Sep 2, 2026
@arnested

Copy link
Copy Markdown
Owner

I apologize for not responding sooner, @anupamme.

I had an initial look back when you opened the PR.

You are most likely correct in that the action can access go.mod files outside the working directory. But that would merely provide you with access to go.mod files anywhere else on the machine the GitHub Action is running on. If there are any at all, I also hardly see how this presents a security concern since you could also be able to read them from the activities done outside this action.

Then is the extra complication worth the effort?

@anupamme

Copy link
Copy Markdown
Author

Thanks for taking a look, and I agree with the distinction you're making.

The original PR description overstated the security impact. The issue is real in the sense that working-directory can currently resolve outside GITHUB_WORKSPACE and cause the action to read a go.mod elsewhere on the runner, but I agree that this isn't a meaningful security boundary if the workflow itself is already under the attacker's control.

The reason I kept the fix is more about the action's expected behavior: working-directory appears to select the project directory being inspected, so allowing it to escape the workspace can make the action inspect an unrelated go.mod on the runner. The current patch also makes that behavior explicit and adds regression coverage, including symlink escapes.

I'm happy to reframe this as defensive input validation/correctness rather than a high-severity security fix. If you don't think enforcing the workspace boundary is useful enough to justify the additional complexity, I'm also happy to close the PR.

Would you prefer to keep the workspace-boundary validation as a correctness safeguard, or should I close this?

@anupamme anupamme changed the title fix: the working-directory input parameter is accept... in main.js main: keep working-directory resolution inside GITHUB_WORKSPACE Sep 14, 2026
@arnested

Copy link
Copy Markdown
Owner

Hi @anupamme

After another look I think it would be fine to add your fix. The added complexity is on a fine level, I think.

In the current form npm run test fails though?

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants