Skip to content

Commit bae3120

Browse files
committed
fix(ci): prevent shell injection via PR title in custom-version workflows
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
1 parent 9bfdcb4 commit bae3120

2 files changed

Lines changed: 54 additions & 71 deletions

File tree

.github/workflows/lint-custom-version.yml

Lines changed: 27 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -58,21 +58,18 @@ jobs:
5858

5959
- name: Extract version from PR
6060
id: extract-version
61-
shell: bash
61+
shell: pwsh
62+
env:
63+
PR_TITLE: ${{ github.event.pull_request.title }}
6264
run: |
63-
# Extract version from PR title only
64-
PR_TITLE="${{ github.event.pull_request.title }}"
65-
66-
# Search for version pattern in title (any x.y.z.dev version)
67-
VERSION=$(echo "$PR_TITLE" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.dev[0-9]+' | head -1)
68-
69-
if [ -z "$VERSION" ]; then
70-
echo "No version found in PR title. Please include version in title like: 2.0.65.dev1004030443"
65+
$match = [regex]::Match($env:PR_TITLE, '[0-9]+\.[0-9]+\.[0-9]+\.dev[0-9]+')
66+
if (-not $match.Success) {
67+
Write-Output "No version found in PR title. Please include version in title like: 2.0.65.dev1004030443"
7168
exit 1
72-
fi
73-
74-
echo "Extracted version: $VERSION"
75-
echo "version=$VERSION" >> $GITHUB_OUTPUT
69+
}
70+
$version = $match.Value
71+
Write-Output "Extracted version: $version"
72+
"version=$version" | Add-Content -Path $env:GITHUB_OUTPUT
7673
7774
- name: Setup uv
7875
uses: astral-sh/setup-uv@v5
@@ -85,31 +82,26 @@ jobs:
8582
python-version-file: "packages/${{ matrix.package }}/.python-version"
8683

8784
- name: Modify pyproject.toml for custom UiPath version
88-
shell: bash
85+
shell: pwsh
86+
env:
87+
UIPATH_VERSION: ${{ steps.extract-version.outputs.version }}
8988
run: |
90-
# Backup original pyproject.toml
91-
cp pyproject.toml pyproject.toml.backup
92-
93-
# Update the uipath dependency to the custom version
94-
sed -i 's|"uipath>=.*"|"uipath==${{ steps.extract-version.outputs.version }}"|' pyproject.toml
89+
Copy-Item pyproject.toml pyproject.toml.backup
9590
91+
$content = Get-Content pyproject.toml -Raw
92+
$content = $content -replace '"uipath>=[^"]*"', "`"uipath==$env:UIPATH_VERSION`""
9693
94+
if ($content -notmatch '\[tool\.uv\.sources\]') {
95+
$content = $content.TrimEnd() + "`n`n[tool.uv.sources]`nuipath = { index = `"testpypi`" }`n"
96+
} elseif ($content -notmatch 'uipath\s*=\s*\{\s*index\s*=\s*"testpypi"\s*\}') {
97+
$content = $content -replace '(\[tool\.uv\.sources\])', "`$1`nuipath = { index = `"testpypi`" }"
98+
}
9799
98-
# Add or update [tool.uv.sources] section if it doesn't exist
99-
if ! grep -q "\[tool\.uv\.sources\]" pyproject.toml; then
100-
echo "" >> pyproject.toml
101-
echo "[tool.uv.sources]" >> pyproject.toml
102-
echo 'uipath = { index = "testpypi" }' >> pyproject.toml
103-
else
104-
# Update existing sources if needed
105-
if ! grep -q 'uipath = { index = "testpypi" }' pyproject.toml; then
106-
sed -i '/\[tool\.uv\.sources\]/a uipath = { index = "testpypi" }' pyproject.toml
107-
fi
108-
fi
100+
Set-Content -Path pyproject.toml -Value $content -NoNewline
109101
110-
echo "Modified pyproject.toml to use UiPath version ${{ steps.extract-version.outputs.version }} from testpypi"
111-
echo "=== Modified pyproject.toml content ==="
112-
grep -A5 -B5 "uipath\|testpypi" pyproject.toml || true
102+
Write-Output "Modified pyproject.toml to use UiPath version $env:UIPATH_VERSION from testpypi"
103+
Write-Output "=== Modified pyproject.toml content ==="
104+
Get-Content pyproject.toml
113105
114106
- name: Install dependencies
115107
run: uv sync --all-extras
@@ -125,6 +117,5 @@ jobs:
125117

126118
- name: Restore original pyproject.toml
127119
if: always()
128-
shell: bash
129-
run: |
130-
mv pyproject.toml.backup pyproject.toml
120+
shell: pwsh
121+
run: Move-Item -Force pyproject.toml.backup pyproject.toml

.github/workflows/test-custom-version.yml

Lines changed: 27 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -67,21 +67,18 @@ jobs:
6767

6868
- name: Extract version from PR
6969
id: extract-version
70-
shell: bash
70+
shell: pwsh
71+
env:
72+
PR_TITLE: ${{ github.event.pull_request.title }}
7173
run: |
72-
# Extract version from PR title only
73-
PR_TITLE="${{ github.event.pull_request.title }}"
74-
75-
# Search for version pattern in title (any x.y.z.dev version)
76-
VERSION=$(echo "$PR_TITLE" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.dev[0-9]+' | head -1)
77-
78-
if [ -z "$VERSION" ]; then
79-
echo "No version found in PR title. Please include version in title like: 2.0.65.dev1004030443"
74+
$match = [regex]::Match($env:PR_TITLE, '[0-9]+\.[0-9]+\.[0-9]+\.dev[0-9]+')
75+
if (-not $match.Success) {
76+
Write-Output "No version found in PR title. Please include version in title like: 2.0.65.dev1004030443"
8077
exit 1
81-
fi
82-
83-
echo "Extracted version: $VERSION"
84-
echo "version=$VERSION" >> $GITHUB_OUTPUT
78+
}
79+
$version = $match.Value
80+
Write-Output "Extracted version: $version"
81+
"version=$version" | Add-Content -Path $env:GITHUB_OUTPUT
8582
8683
- name: Setup uv
8784
uses: astral-sh/setup-uv@v5
@@ -94,31 +91,26 @@ jobs:
9491
python-version: ${{ matrix.python-version }}
9592

9693
- name: Modify pyproject.toml for custom UiPath version
97-
shell: bash
94+
shell: pwsh
95+
env:
96+
UIPATH_VERSION: ${{ steps.extract-version.outputs.version }}
9897
run: |
99-
# Backup original pyproject.toml
100-
cp pyproject.toml pyproject.toml.backup
101-
102-
# Update the uipath dependency to the custom version
103-
sed -i 's|"uipath>=.*"|"uipath==${{ steps.extract-version.outputs.version }}"|' pyproject.toml
98+
Copy-Item pyproject.toml pyproject.toml.backup
10499
100+
$content = Get-Content pyproject.toml -Raw
101+
$content = $content -replace '"uipath>=[^"]*"', "`"uipath==$env:UIPATH_VERSION`""
105102
103+
if ($content -notmatch '\[tool\.uv\.sources\]') {
104+
$content = $content.TrimEnd() + "`n`n[tool.uv.sources]`nuipath = { index = `"testpypi`" }`n"
105+
} elseif ($content -notmatch 'uipath\s*=\s*\{\s*index\s*=\s*"testpypi"\s*\}') {
106+
$content = $content -replace '(\[tool\.uv\.sources\])', "`$1`nuipath = { index = `"testpypi`" }"
107+
}
106108
107-
# Add or update [tool.uv.sources] section if it doesn't exist
108-
if ! grep -q "\[tool\.uv\.sources\]" pyproject.toml; then
109-
echo "" >> pyproject.toml
110-
echo "[tool.uv.sources]" >> pyproject.toml
111-
echo 'uipath = { index = "testpypi" }' >> pyproject.toml
112-
else
113-
# Update existing sources if needed
114-
if ! grep -q 'uipath = { index = "testpypi" }' pyproject.toml; then
115-
sed -i '/\[tool\.uv\.sources\]/a uipath = { index = "testpypi" }' pyproject.toml
116-
fi
117-
fi
109+
Set-Content -Path pyproject.toml -Value $content -NoNewline
118110
119-
echo "Modified pyproject.toml to use UiPath version ${{ steps.extract-version.outputs.version }} from testpypi"
120-
echo "=== Modified pyproject.toml content ==="
121-
grep -A5 -B5 "uipath\|testpypi" pyproject.toml || true
111+
Write-Output "Modified pyproject.toml to use UiPath version $env:UIPATH_VERSION from testpypi"
112+
Write-Output "=== Modified pyproject.toml content ==="
113+
Get-Content pyproject.toml
122114
123115
- name: Install dependencies with specific UiPath version
124116
run: uv sync --all-extras --python ${{ matrix.python-version }}
@@ -132,5 +124,5 @@ jobs:
132124

133125
- name: Restore original pyproject.toml
134126
if: always()
135-
shell: bash
136-
run: mv pyproject.toml.backup pyproject.toml
127+
shell: pwsh
128+
run: Move-Item -Force pyproject.toml.backup pyproject.toml

0 commit comments

Comments
 (0)