Skip to content

Mutable GitHub Actions Enable CI Supply Chain Attack #288

@ckeshava

Description

@ckeshava

Vulnerability Overview

  • Repository: XRPLF/xrpl-rust
  • Type: Dependency Vulnerability
  • Severity: LOW
  • Confidence: MEDIUM
  • Location: .github/workflows/build_and_lint.yml (lines 18)

Description

The CI workflows run third-party GitHub Actions from mutable refs instead of immutable commit SHAs. If an upstream tag moves or is compromised, GitHub Actions can execute attacker-controlled code in build, test, and coverage jobs with the runner environment and default token.

Detailed Analysis

Code Context

This repository is a Rust library with GitHub Actions workflows for build/lint, unit tests, integration tests, and coverage. These jobs run on pushes and pull requests, and they install the Rust toolchain and cargo-llvm-cov before building and testing the code.

Vulnerability Details

The workflows should pin third-party actions to immutable commit SHAs. Instead, they use dtolnay/rust-toolchain@stable in four workflows and taiki-e/install-action@cargo-llvm-cov in unit tests. Those mutable refs can resolve to different code on later runs.

Impact

A malicious upstream ref could run arbitrary code in CI, exposing the job environment and GITHUB_TOKEN, tampering with test results or build artifacts, and potentially changing repository state if token permissions allow. The repository does not show deployment or publish secrets in these jobs.

Exploit Scenario

An attacker gains control of the upstream action repository or tag, then force-pushes malicious code to stable or cargo-llvm-cov. The next push or pull request triggers these workflows, the runner fetches the poisoned action, and the payload steals environment data or alters CI output.

Reachability Evidence

Verdict: UNCERTAIN
Summary: The workflows use mutable third-party action refs, but this repository does not reveal upstream tag protections, account compromise status, or the effective secret and GITHUB_TOKEN permissions. Exploitability therefore remains unconfirmed.

Condition Assessments

UNCERTAIN: The GitHub account of dtolnay (for rust-toolchain) or taiki-e (for install-action) is compromised, or their action repositories allow force-pushing to the referenced tags.

The repository clearly uses third-party GitHub Actions through mutable refs rather than immutable commit SHAs, so a later upstream retag or branch movement would be consumed by CI. For example, unit_test.yml uses dtolnay/rust-toolchain@stable and taiki-e/install-action@cargo-llvm-cov, both of which are mutable names. However, this codebase contains no evidence about the external dtolnay or taiki-e accounts, their repository tag-protection settings, or whether force-pushing those refs is possible. Therefore the code proves trust in mutable upstream refs, but it cannot prove the specific precondition that those upstream accounts are compromised or their tags are mutable in practice.

.github/workflows/unit_test.yml:16-42

    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo registry
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-test-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: |
            ${{ runner.os }}-cargo-test-

      - name: Test with default features
        run: cargo test --release
        env:
          RUST_BACKTRACE: 1

      - name: Test for no_std
        run: cargo test --release --no-default-features --features embassy-rt,core,utils,wallet,models,helpers,websocket,json-rpc
        env:
          RUST_BACKTRACE: 1

      - name: Install cargo-llvm-cov
        uses: taiki-e/install-action@cargo-llvm-cov

UNCERTAIN: The CI workflows have access to repository secrets or a GITHUB_TOKEN with write permissions that would be valuable after exfiltration.

I found no workflow code that explicitly references ${{ secrets.* }}, sets a custom token:, or declares permissions:. The CI files are ordinary test/build workflows, and CONTRIBUTING.md says publishing is still manual, which weakens the case for obvious release secrets in these jobs. But the absence of permissions: in version-controlled workflow files means the effective GITHUB_TOKEN scope is inherited from GitHub repository or organization settings outside this repository, and GitHub Actions normally still provides a token. As a result, the codebase does not prove valuable secrets or write-scoped token access, but it also does not rule them out.

.github/workflows/build_and_lint.yml:1-20

on:
  push:
    branches:
      - dev
  pull_request:
    branches:
      - main
      - dev

name: Build & Lint

jobs:
  build_and_lint:
    name: Build & Lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt, clippy

Metadata

Metadata

Assignees

No one assigned

    Labels

    AI TriageIssue reported via AI-assisted analysis; needs human triage

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions