mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
chore: harden GitHub Actions against script injection patterns (#50708)
chore: harden GitHub Actions against script injection patterns (#50512) * fix: harden GitHub Actions against script injection vulnerabilities Replace direct ${{ }} expression interpolation in run: blocks with environment variables to prevent script injection attacks. Changes: - archaeologist-dig.yml: move clone_url, head.sha, base.ref to env vars - non-maintainer-dependency-change.yml: move user.login to env var - issue-unlabeled.yml: move toJSON(labels) to env var - issue-labeled.yml: move issue.number to env var - pipeline-electron-lint.yml: validate chromium_revision format - cipd-install/action.yml: move all inputs to env vars and quote them - set-chromium-cookie/action.yml: reference secrets via $ENV_VAR - Add security comments to all 5 pull_request_target workflows https://claude.ai/code/session_01UUWmLxn5hyyxrhK8rGxU2s * fix: allow version strings in chromium_revision validation The previous regex `^[a-f0-9]+$` only matched git SHAs but chromium_revision is a version string like `148.0.7741.0`. Broaden to `^[a-zA-Z0-9._-]+$` which still blocks shell metacharacters. https://claude.ai/code/session_01UUWmLxn5hyyxrhK8rGxU2s --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
38
.github/actions/cipd-install/action.yml
vendored
38
.github/actions/cipd-install/action.yml
vendored
@@ -22,30 +22,50 @@ runs:
|
||||
steps:
|
||||
- name: Delete wrong ${{ inputs.dependency }}
|
||||
shell: bash
|
||||
env:
|
||||
CIPD_ROOT_PREFIX: ${{ inputs.cipd-root-prefix-path }}
|
||||
INSTALLATION_DIR: ${{ inputs.installation-dir }}
|
||||
run : |
|
||||
rm -rf ${{ inputs.cipd-root-prefix-path }}${{ inputs.installation-dir }}
|
||||
rm -rf "${CIPD_ROOT_PREFIX}${INSTALLATION_DIR}"
|
||||
- name: Create ensure file for ${{ inputs.dependency }}
|
||||
if: ${{ inputs.dependency-version == '' }}
|
||||
shell: bash
|
||||
env:
|
||||
PACKAGE: ${{ inputs.package }}
|
||||
DEPS_FILE: ${{ inputs.deps-file }}
|
||||
INSTALLATION_DIR: ${{ inputs.installation-dir }}
|
||||
DEPENDENCY: ${{ inputs.dependency }}
|
||||
run: |
|
||||
echo '${{ inputs.package }}' `e d gclient getdep --deps-file=${{ inputs.deps-file }} -r '${{ inputs.installation-dir }}:${{ inputs.package }}'` > ${{ inputs.dependency }}_ensure_file
|
||||
cat ${{ inputs.dependency }}_ensure_file
|
||||
echo "$PACKAGE" $(e d gclient getdep --deps-file="$DEPS_FILE" -r "${INSTALLATION_DIR}:${PACKAGE}") > "${DEPENDENCY}_ensure_file"
|
||||
cat "${DEPENDENCY}_ensure_file"
|
||||
|
||||
- name: Create ensure file for ${{ inputs.dependency }} from dependency-version
|
||||
if: ${{ inputs.dependency-version != '' }}
|
||||
shell: bash
|
||||
env:
|
||||
PACKAGE: ${{ inputs.package }}
|
||||
DEPENDENCY_VERSION: ${{ inputs.dependency-version }}
|
||||
DEPENDENCY: ${{ inputs.dependency }}
|
||||
run: |
|
||||
echo '${{ inputs.package }} ${{ inputs.dependency-version }}' > ${{ inputs.dependency }}_ensure_file
|
||||
cat ${{ inputs.dependency }}_ensure_file
|
||||
echo "$PACKAGE $DEPENDENCY_VERSION" > "${DEPENDENCY}_ensure_file"
|
||||
cat "${DEPENDENCY}_ensure_file"
|
||||
- name: CIPD installation of ${{ inputs.dependency }} (macOS)
|
||||
if: ${{ inputs.target-platform != 'win' }}
|
||||
shell: bash
|
||||
env:
|
||||
CIPD_ROOT_PREFIX: ${{ inputs.cipd-root-prefix-path }}
|
||||
INSTALLATION_DIR: ${{ inputs.installation-dir }}
|
||||
DEPENDENCY: ${{ inputs.dependency }}
|
||||
run: |
|
||||
echo "ensuring ${{ inputs.dependency }}"
|
||||
e d cipd ensure --root ${{ inputs.cipd-root-prefix-path }}${{ inputs.installation-dir }} -ensure-file ${{ inputs.dependency }}_ensure_file
|
||||
echo "ensuring $DEPENDENCY"
|
||||
e d cipd ensure --root "${CIPD_ROOT_PREFIX}${INSTALLATION_DIR}" -ensure-file "${DEPENDENCY}_ensure_file"
|
||||
- name: CIPD installation of ${{ inputs.dependency }} (Windows)
|
||||
if: ${{ inputs.target-platform == 'win' }}
|
||||
shell: powershell
|
||||
env:
|
||||
CIPD_ROOT_PREFIX: ${{ inputs.cipd-root-prefix-path }}
|
||||
INSTALLATION_DIR: ${{ inputs.installation-dir }}
|
||||
DEPENDENCY: ${{ inputs.dependency }}
|
||||
run: |
|
||||
echo "ensuring ${{ inputs.dependency }} on Windows"
|
||||
e d cipd ensure --root ${{ inputs.cipd-root-prefix-path }}${{ inputs.installation-dir }} -ensure-file ${{ inputs.dependency }}_ensure_file
|
||||
echo "ensuring $env:DEPENDENCY on Windows"
|
||||
e d cipd ensure --root "$env:CIPD_ROOT_PREFIX$env:INSTALLATION_DIR" -ensure-file "$($env:DEPENDENCY)_ensure_file"
|
||||
|
||||
@@ -7,7 +7,7 @@ runs:
|
||||
if: ${{ runner.os != 'Windows' }}
|
||||
shell: bash
|
||||
run: |
|
||||
if [[ -z "${{ env.CHROMIUM_GIT_COOKIE }}" ]]; then
|
||||
if [[ -z "$CHROMIUM_GIT_COOKIE" ]]; then
|
||||
echo "CHROMIUM_GIT_COOKIE is not set - cannot authenticate."
|
||||
exit 0
|
||||
fi
|
||||
@@ -18,9 +18,7 @@ runs:
|
||||
|
||||
git config --global http.cookiefile ~/.gitcookies
|
||||
|
||||
tr , \\t <<\__END__ >>~/.gitcookies
|
||||
${{ env.CHROMIUM_GIT_COOKIE }}
|
||||
__END__
|
||||
echo "$CHROMIUM_GIT_COOKIE" | tr , \\t >>~/.gitcookies
|
||||
eval 'set -o history' 2>/dev/null || unsetopt HIST_IGNORE_SPACE 2>/dev/null
|
||||
|
||||
RESPONSE=$(curl -s -b ~/.gitcookies https://chromium-review.googlesource.com/a/accounts/self)
|
||||
@@ -42,7 +40,7 @@ runs:
|
||||
)
|
||||
|
||||
git config --global http.cookiefile "%USERPROFILE%\.gitcookies"
|
||||
powershell -noprofile -nologo -command Write-Output "${{ env.CHROMIUM_GIT_COOKIE_WINDOWS_STRING }}" >>"%USERPROFILE%\.gitcookies"
|
||||
powershell -noprofile -nologo -command Write-Output $env:CHROMIUM_GIT_COOKIE_WINDOWS_STRING >>"%USERPROFILE%\.gitcookies"
|
||||
|
||||
curl -s -b "%USERPROFILE%\.gitcookies" https://chromium-review.googlesource.com/a/accounts/self > response.txt
|
||||
|
||||
|
||||
20
.github/workflows/archaeologist-dig.yml
vendored
20
.github/workflows/archaeologist-dig.yml
vendored
@@ -21,17 +21,21 @@ jobs:
|
||||
with:
|
||||
node-version: 24.12.x
|
||||
- name: Setting Up Dig Site
|
||||
env:
|
||||
CLONE_URL: ${{ github.event.pull_request.head.repo.clone_url }}
|
||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
BASE_REF: ${{ github.event.pull_request.base.ref }}
|
||||
run: |
|
||||
echo "remote: ${{ github.event.pull_request.head.repo.clone_url }}"
|
||||
echo "sha ${{ github.event.pull_request.head.sha }}"
|
||||
echo "base ref ${{ github.event.pull_request.base.ref }}"
|
||||
git clone https://github.com/electron/electron.git electron
|
||||
echo "remote: $CLONE_URL"
|
||||
echo "sha $HEAD_SHA"
|
||||
echo "base ref $BASE_REF"
|
||||
git clone https://github.com/electron/electron.git electron
|
||||
cd electron
|
||||
mkdir -p artifacts
|
||||
git remote add fork ${{ github.event.pull_request.head.repo.clone_url }} && git fetch fork
|
||||
git checkout ${{ github.event.pull_request.head.sha }}
|
||||
git merge-base origin/${{ github.event.pull_request.base.ref }} HEAD > .dig-old
|
||||
echo ${{ github.event.pull_request.head.sha }} > .dig-new
|
||||
git remote add fork "$CLONE_URL" && git fetch fork
|
||||
git checkout "$HEAD_SHA"
|
||||
git merge-base "origin/$BASE_REF" HEAD > .dig-old
|
||||
echo "$HEAD_SHA" > .dig-new
|
||||
cp .dig-old artifacts
|
||||
|
||||
- name: Generating Types for SHA in .dig-new
|
||||
|
||||
3
.github/workflows/issue-labeled.yml
vendored
3
.github/workflows/issue-labeled.yml
vendored
@@ -61,9 +61,10 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_REPO: electron/electron
|
||||
ISSUE_NUMBER: ${{ github.event.issue.number }}
|
||||
run: |
|
||||
set -eo pipefail
|
||||
COMMENT_COUNT=$(gh issue view ${{ github.event.issue.number }} --comments --json comments | jq '[ .comments[] | select(.author.login == "electron-issue-triage" or .authorAssociation == "OWNER" or .authorAssociation == "MEMBER") | select(.body | startswith("<!-- blocked/need-repro -->")) ] | length')
|
||||
COMMENT_COUNT=$(gh issue view "$ISSUE_NUMBER" --comments --json comments | jq '[ .comments[] | select(.author.login == "electron-issue-triage" or .authorAssociation == "OWNER" or .authorAssociation == "MEMBER") | select(.body | startswith("<!-- blocked/need-repro -->")) ] | length')
|
||||
if [[ $COMMENT_COUNT -eq 0 ]]; then
|
||||
echo "SHOULD_COMMENT=1" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
4
.github/workflows/issue-unlabeled.yml
vendored
4
.github/workflows/issue-unlabeled.yml
vendored
@@ -16,9 +16,11 @@ jobs:
|
||||
steps:
|
||||
- name: Check for any blocked labels
|
||||
id: check-for-blocked-labels
|
||||
env:
|
||||
LABELS_JSON: ${{ toJSON(github.event.issue.labels.*.name) }}
|
||||
run: |
|
||||
set -eo pipefail
|
||||
BLOCKED_LABEL_COUNT=$(echo '${{ toJSON(github.event.issue.labels.*.name) }}' | jq '[ .[] | select(startswith("blocked/")) ] | length')
|
||||
BLOCKED_LABEL_COUNT=$(echo "$LABELS_JSON" | jq '[ .[] | select(startswith("blocked/")) ] | length')
|
||||
if [[ $BLOCKED_LABEL_COUNT -eq 0 ]]; then
|
||||
echo "NOT_BLOCKED=1" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
@@ -10,6 +10,10 @@ on:
|
||||
- '.yarn/**'
|
||||
- '.yarnrc.yml'
|
||||
|
||||
# SECURITY: This workflow uses pull_request_target and has access to secrets.
|
||||
# Do NOT checkout or run code from the PR head. All code execution must use
|
||||
# the base branch only. Adding a ref to PR head would expose secrets to
|
||||
# untrusted code.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
@@ -45,5 +49,6 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PR_URL: ${{ github.event.pull_request.html_url }}
|
||||
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
|
||||
run: |
|
||||
printf "<!-- disallowed-non-maintainer-change -->\n\nHello @${{ github.event.pull_request.user.login }}! It looks like this pull request touches one of our dependency or CI files, and per [our contribution policy](https://github.com/electron/electron/blob/main/CONTRIBUTING.md#dependencies-upgrades-policy) we do not accept these types of changes in PRs." | gh pr review $PR_URL -r --body-file=-
|
||||
printf "<!-- disallowed-non-maintainer-change -->\n\nHello @${PR_AUTHOR}! It looks like this pull request touches one of our dependency or CI files, and per [our contribution policy](https://github.com/electron/electron/blob/main/CONTRIBUTING.md#dependencies-upgrades-policy) we do not accept these types of changes in PRs." | gh pr review $PR_URL -r --body-file=-
|
||||
|
||||
8
.github/workflows/pipeline-electron-lint.yml
vendored
8
.github/workflows/pipeline-electron-lint.yml
vendored
@@ -46,6 +46,10 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)"
|
||||
if [[ ! "$chromium_revision" =~ ^[a-zA-Z0-9._-]+$ ]]; then
|
||||
echo "::error::Invalid chromium_revision: $chromium_revision"
|
||||
exit 1
|
||||
fi
|
||||
gn_version="$(curl -sL -b ~/.gitcookies "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/DEPS?format=TEXT" | base64 -d | grep gn_version | head -n1 | cut -d\' -f4)"
|
||||
|
||||
cipd ensure -ensure-file - -root . <<-CIPD
|
||||
@@ -60,6 +64,10 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)"
|
||||
if [[ ! "$chromium_revision" =~ ^[a-zA-Z0-9._-]+$ ]]; then
|
||||
echo "::error::Invalid chromium_revision: $chromium_revision"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p src/buildtools
|
||||
curl -sL -b ~/.gitcookies "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/buildtools/DEPS?format=TEXT" | base64 -d > src/buildtools/DEPS
|
||||
|
||||
4
.github/workflows/pull-request-labeled.yml
vendored
4
.github/workflows/pull-request-labeled.yml
vendored
@@ -4,6 +4,10 @@ on:
|
||||
pull_request_target:
|
||||
types: [labeled]
|
||||
|
||||
# SECURITY: This workflow uses pull_request_target and has access to secrets.
|
||||
# Do NOT checkout or run code from the PR head. All code execution must use
|
||||
# the base branch only. Adding a ref to PR head would expose secrets to
|
||||
# untrusted code.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -4,6 +4,10 @@ on:
|
||||
pull_request_target:
|
||||
types: [opened, synchronize]
|
||||
|
||||
# SECURITY: This workflow uses pull_request_target and has access to secrets.
|
||||
# Do NOT checkout or run code from the PR head. All code execution must use
|
||||
# the base branch only. Adding a ref to PR head would expose secrets to
|
||||
# untrusted code.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
|
||||
Reference in New Issue
Block a user