Skip to content

Possible a run: step pipes the output of curl or wget directly into a shell interpreter in release.yml #638

Description

@begininvoke

Came across something in .github/workflows/release.yml around line 144 that looked worth flagging.

The workflow uses the dangerous 'curl | bash' pattern to install Rust via rustup. The script from https://sh.rustup.rs is downloaded and piped directly into sh, which means if the remote server is compromised or the URL hijacked, arbitrary code executes in the CI runner with full privileges. This is a high-risk supply chain vulnerability (CWE-78) because the CI runner often has access to secrets and deployment credentials. The fix is to download the script first, verify its integrity (e.g., SHA256 checksum against a known good value), and then execute it.

The code in question
        run: |
          cd wrappers

          # Resolve effective version: use input for manual dry-runs, tag for real releases
          if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
            RAW_VERSION="${{ inputs.version }}"
          else
            RAW_VERSION="${{ github.ref_name }}"
          fi

          if [[ -z "${RAW_VERSION}" ]]; then
            echo "Version must not be empty"
            exit 1
          fi

          NORMALIZED_VERSION="${RAW_VERSION#v}"
          EFFECTIVE_VERSION="v${NORMALIZED_VERSION}"
          echo "Building version: ${EFFECTIVE_VERSION}"

          # Add postgres package repo and install requested postgres version
          sudo apt update
          sudo apt remove -y postgres*
          sudo apt -y install curl ca-certificates pkg-config libssl-dev
          sudo install -d /usr/share/postgresql-common/pgdg
          sudo curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc --fail https://www.postgresql.org/media/keys/ACCC4CF8.asc
          . /etc/os-release
          sudo sh -c "echo 'deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://apt.postgresql.org/pub/repos/apt $VERSION_CODENAME-pgdg main' > /etc/apt/sources.list.d/pgdg.list"
          sudo apt update -y -qq --fix-missing
          sudo apt -y install postgresql-${{ matrix.postgres }} postgresql-server-dev-${{ matrix.postgres }}
          sudo apt -y autoremove && sudo apt -y clean
          sudo chmod a+rwx `/usr/lib/postgresql/${{ matrix.postgres }}/bin/pg_config --pkglibdir` `/usr/lib/postgresql/${{ matrix.postgres }}/bin/pg_config --sharedir`/extension /var/run/postgresql/

          # Ensure installed pg_config is first on path
          export PATH=/usr/lib/postgresql/${{ matrix.postgres }}/bin:$PATH

          # Extra toolchain + linker config for arm64
          if [[ "${{ matrix.box.arch }}" == "arm64" ]]; then
            sudo apt update
            sudo apt install -y lld
            export RUSTFLAGS="-C link-arg=-fuse-ld=lld"
            export CFLAGS="${CFLAGS:-} -fPIC"
            export CXXFLAGS="${CXXFLAGS:-} -fPIC"
          fi

          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path --profile minimal --default-toolchain 1.97.1 && \
            rustup --version && \
            rustc --version && \
            cargo --version

          # Ensure cargo/rust on path
          source "$HOME/.cargo/env"

          cargo install --locked cargo-pgrx --version ${{ matrix.pgrx_version }}
          cargo pgrx init --pg${{ matrix.postgres }}=/usr/lib/postgresql/${{ matrix.postgres }}/bin/pg_config

          # selects the pgVer from pg_config on path
          # https://github.com/tcdi/pgrx/issues/288
          cargo pgrx package --no-default-features --features pg${{ matrix.postgres }},${{ matrix.features }}

          # Extension version and path
          extension_version=${EFFECTIVE_VERSION}
          extension_dir=../target/release/${{ matrix.extension_name }}-pg${{ matrix.postgres }}/usr/share/postgresql/${{ matrix.postgres }}/extension
          # strip the leading v
          deb_version=${extension_version:1}

          # copy schema file to version update sql files
          for tag in $(git tag -l "v*"); do
            if [[ $tag != $extension_version ]]; then
              prev_version=${tag:1}
              cp ${extension_dir}/${{ matrix.extension_name }}--${deb_version}.sql ${extension_dir}/${{ matrix.extension_name }}--${prev_version}--${deb_version}.sql
            fi
          done

          # Create installable package
          mkdir archive
          cp `find ../target/release -type f -name "${{ matrix.extension_name }}*"` archive

          # name of the package directory before packaging
          package_dir=${{ matrix.extension_name }}-${EFFECTIVE_VERSION}-pg${{ matrix.postgres }}-${{ matrix.box.arch }}-linux-gnu

          # Copy files into directory structure
          mkdir -p ${pa...

Something like this might fix it:

```diff
         # Ensure installed pg_config is first on path
         export PATH=/usr/lib/postgresql/${{ matrix.postgres }}/bin:$PATH
 
         # Extra toolchain + linker config for arm64
         if [[ "${{ matrix.box.arch }}" == "arm64" ]]; then
           sudo apt update
           sudo apt install -y lld
           export RUSTFLAGS="-C link-arg=-fuse-ld=lld"
           export CFLAGS="${CFLAGS:-} -fPIC"
           export CXXFLAGS="${CXXFLAGS:-} -fPIC"
         fi
 
-        curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path --profile minimal --default-toolchain 1.97.1 && \
-          rustup --version && \
-          rustc --version && \
-          cargo --version
+        # Download rustup installer to a file for verification
+        curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o rustup-init.sh
+        # TODO: Verify checksum of rustup-init.sh against a known good value (e.g., from https://rustup.rs/)
+        # Example: echo "<expected-sha256>  rustup-init.sh" | sha256sum -c -
+        sh rustup-init.sh -s -- -y --no-modify-path --profile minimal --default-toolchain 1.97.1 && \
+          rustup --version && \
+          rustc --version && \
+          cargo --version
 
         # Ensure cargo/rust on path
         source "$HOME/.cargo/env"
```

For reference: rule yaml.github-actions.security.gha-curl-pipe-shell.gha-curl-pipe-shell, CWE-78 (Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')). Rated high.

I do not maintain this project, so I may well be missing context — if this is intentional or already handled elsewhere, please just close it.


Found with automated scanning (RedGem) and reviewed before opening. If it is not useful, closing it is completely fine.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions