Skip to content

fix(ci): prevent shell injection via PR title in custom-version workflows#349

Merged
ionmincu merged 1 commit into
mainfrom
security/prodev-239-pr-title-injection
May 20, 2026
Merged

fix(ci): prevent shell injection via PR title in custom-version workflows#349
ionmincu merged 1 commit into
mainfrom
security/prodev-239-pr-title-injection

Conversation

@ionmincu

Copy link
Copy Markdown
Collaborator

Summary

  • lint-custom-version.yml and test-custom-version.yml interpolated github.event.pull_request.title directly into the bash run: block via ${{ ... }}. Because that interpolation happens before the shell parses the script, a PR title containing " plus &&/$(...) could break out of the string literal and execute arbitrary commands on the runner — including writing to $GITHUB_ENV to poison later steps.
  • Same vulnerability class as the original PRODEV-239 report on the langchain repo's publish-dev.yml, flagged in the issue comments.
  • Risk for test-custom-version.yml is higher: a later step runs uv run pytest with UIPATH_URL / UIPATH_CLIENT_ID / UIPATH_CLIENT_SECRET in env, so a hijacked early step could drop a malicious conftest/build hook to exfiltrate them.

Fix

  • Pass the PR title via the step's env: block instead of ${{ }} interpolation — the shell parser only ever sees the env-var reference, never the attacker-controlled value as code.
  • Convert the affected bash steps to PowerShell Core (pwsh) for consistency.
  • Regex constraint on the extracted version ([0-9]+\.[0-9]+\.[0-9]+\.dev[0-9]+) is preserved, so the Modify pyproject.toml step's input is still safe even before reaching Set-Content.

POC the fix blocks

PR title:

test" && echo "UV_PUBLISH_URL=https://attacker.example" >> $GITHUB_ENV && echo "

Before: writes attacker-controlled env vars for later steps.
After: the title is read as data from $env:PR_TITLE, never executed.

Test plan

  • Open a test PR with the test-core-dev-version label, a valid title (e.g. bump uipath to 2.0.65.dev1004030443), and a change under packages/** — Extract version step should succeed.
  • Open a test PR with a title missing the version pattern — Extract step should fail cleanly with the existing error message.
  • Verify Modify pyproject.toml correctly inserts/preserves [tool.uv.sources] and uipath = { index = "testpypi" } for each detected package.

Tracking: PRODEV-239

…lows

The Extract version step interpolated `github.event.pull_request.title`
directly into the bash script via `${{ ... }}`, which expands before the
shell parses it. A PR title containing `"` plus `&&` or `$(...)` could
break out of the string literal and execute arbitrary commands on the
runner, including writing to `$GITHUB_ENV` to poison later steps that
have access to UIPATH_* secrets.

Moves the title into an env var (which the shell parser treats as data,
never code) and rewrites the affected steps in PowerShell Core for
consistency with the already-secured publish-dev.yml.

Tracking: PRODEV-239
Copilot AI review requested due to automatic review settings May 20, 2026 12:49
@sonarqubecloud

Copy link
Copy Markdown

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.

Pull request overview

This PR hardens the lint-custom-version.yml and test-custom-version.yml GitHub Actions workflows against shell injection by ensuring the PR title is treated strictly as data when extracting the custom x.y.z.devNNN UiPath version.

Changes:

  • Pass the PR title into the extraction step via env: instead of interpolating it directly into a run: script.
  • Switch the affected steps from bash to pwsh and implement version extraction using .NET regex matching.
  • Update the pyproject modification logic in PowerShell while preserving the same version regex constraint and ensuring [tool.uv.sources] includes uipath = { index = "testpypi" }.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
.github/workflows/test-custom-version.yml Prevents PR-title-driven shell injection and updates pyproject editing to PowerShell across Ubuntu/Windows matrix runs.
.github/workflows/lint-custom-version.yml Applies the same PR-title handling hardening and PowerShell-based pyproject update in the lint workflow.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@ionmincu ionmincu merged commit bb2385d into main May 20, 2026
55 checks passed
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