Skip to content

Conversation

@caxu-rh
Copy link
Contributor

@caxu-rh caxu-rh commented Aug 1, 2025

This change addresses several attack vectors and weaknesses which have been seen in the wild over the past few years:

  • Template injection. Instead of directly referencing GitHub Actions variables ${{ ... }} in scripts, where they are added literally, assign the value to an environment variable and use the environment variable in the script. The shell will expand the environment variable and escape any problematic inputs.
  • Pin actions. Third-party actions are often referenced by tags, which are floating and can be re-assigned to a different ref. Instead, refer to third-party actions by a full Git SHA-1 commit hash. The intended tag is still left as a comment, which Dependabot can use for automatic updates. In March 2025, a supply chain attack conducted on the tj-actions/changed-files action resulted in the potential compromise of secrets for any workflows which ran the action without pinning it to a known good version.
  • Excessive token permissions. The GitHub token used inside the workflow run has write access to most things in the repo, unless permissions are explicitly specified. Tools are also available to audit workflows and identify the minimal required set of permissions. We'll tackle this in a follow-up PR.
  • Don't persist credentials in Git checkouts. By default, when using the actions/checkout action, a copy of the workflow credential (e.g. GITHUB_TOKEN) will be persisted in the checked-out repository's .git/config. This makes it easier to perform some further operations in the repo, e.g. pushing a commit or tag later. This can pose an issue if the checked-out repository is then uploaded as an artifact, which can be publicly downloaded.

This change also introduces scanning using zizmor, a static analyzer for GitHub Actions workflows, to run on pushes to main and all pull requests.

@openshift-ci openshift-ci bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 1, 2025
@openshift-ci
Copy link

openshift-ci bot commented Aug 1, 2025

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@coveralls
Copy link

coveralls commented Aug 1, 2025

Coverage Status

coverage: 83.812%. remained the same
when pulling fb1d072 on caxu-rh:github-actions-hardening
into bb06e5a on redhat-openshift-ecosystem:main.

@caxu-rh caxu-rh force-pushed the github-actions-hardening branch 2 times, most recently from 02703ca to 0735e2b Compare August 1, 2025 15:50
@acornett21
Copy link
Contributor

It will probably take a couple of passes to double check everything on this. Since this is such a sweeping change, I think once we feel this is no longer WIP, we setup your fork to cut releases to your own quay and test those workflows as well.

@caxu-rh caxu-rh force-pushed the github-actions-hardening branch from 0735e2b to 1dee373 Compare August 1, 2025 18:04
@caxu-rh
Copy link
Contributor Author

caxu-rh commented Aug 1, 2025

I've reduced the scope of this PR to skip explicitly adding permissions on jobs/workflows for now, instead just leaving TODOs.

In follow-up PRs, we should audit the necessary scope of the tokens for each job using a tool like https://github.com/GitHubSecurityLab/actions-permissions, and then assign the necessary permissions based on findings.

@caxu-rh caxu-rh marked this pull request as ready for review August 1, 2025 19:43
@openshift-ci openshift-ci bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 1, 2025
@openshift-ci openshift-ci bot requested review from bcrochet and skattoju August 1, 2025 19:43
@dcibot
Copy link

dcibot commented Aug 1, 2025

@github-actions
Copy link

github-actions bot commented Aug 4, 2025

Code Review by Gemini

This pull request significantly improves the security posture of your GitHub Actions workflows, addressing several critical attack vectors. The commit message is exceptionally clear, detailing the vulnerabilities addressed and even noting what will be tackled in a follow-up PR.

Here's a detailed review:

General Observations & Strengths

  1. Comprehensive Security Improvements: The PR successfully implements fixes for:

    • Template Injection: By assigning GitHub Actions expressions to environment variables before using them in run scripts, you effectively prevent shell injection vulnerabilities. This is a crucial improvement.
    • Action Pinning: All third-party actions are now pinned to specific Git SHA-1 hashes, eliminating the risk of supply chain attacks through mutable tags. This is a gold standard for GitHub Actions security.
    • Credential Persistence: The actions/checkout action now consistently uses persist-credentials: false, preventing the GITHUB_TOKEN from being written to the .git/config file, which could be leaked if artifacts are uploaded.
    • Static Analysis: The introduction of zizmor for GitHub Actions security scanning is an excellent proactive measure.
  2. Clear Documentation: The commit message is a fantastic example of how to document security changes, explaining the "why" behind each modification and referencing external resources. The TODO comments and zizmor: ignore annotations in the code are also very helpful for tracking future work.

  3. Idiomatic Go: This review is for GitHub Actions workflow files (YAML), not Go code. Therefore, the "Idiomatic Go" aspect is not applicable here.

Specific Feedback and Suggestions

add-release-info-to-pyxis.yml

  • Template Injection Fix: The change to use DATA_PAYLOAD and PYXIS_ENDPOINT environment variables for the curl command is a perfect example of preventing template injection. This is well done.
  • Permissions: As noted by the TODO comment, explicitly setting permissions for this job would be a good follow-up. Given it interacts with external secrets and an API, ensuring it only has the minimum necessary permissions is important.

build-main.yml, build-release.yml, go.yml, release-artifacts.yml

  • Action Pinning: All actions are correctly pinned to SHAs. Excellent.
  • persist-credentials: false: Correctly applied to actions/checkout.
  • Template Injection Fixes: The use of environment variables for echo commands (e.g., REGISTRY_PATHS) is a good practice to prevent potential issues, even if the risk is lower for simple echo statements.
  • Permissions: The TODO comments regarding explicit permissions are appropriate. This is the main remaining area for hardening these workflows.

build-multiarch.yml

  • Template Injection Fixes: The changes to use INPUT_NAME and INPUT_TAG environment variables for buildah manifest and podman manifest commands are well-executed and prevent potential injection.
  • Action Pinning: All actions are correctly pinned to SHAs. Excellent.

check-actions.yml (New File)

  • Purpose: This is a fantastic addition. Running zizmor on push to main and all pull_request events provides continuous security scanning.
  • Permissions: permissions: {} for this workflow is a best practice for security scanning tools that don't need to modify the repository. This is excellent.
  • Action Pinning: Both actions/checkout and zizmorcore/zizmor-action are correctly pinned.

code-review.yml

  • pull_request_target Trigger: The zizmor: ignore[dangerous-triggers] comment correctly identifies the inherent risk of pull_request_target. While necessary for actions that need to write back to the PR (like adding comments/labels), it means the workflow runs with the base repository's permissions, even for untrusted fork PRs. This makes the trustworthiness of the gemini-code-review-action paramount.
  • Workflow-level Permissions: The TODO comment about assigning permissions at the job level rather than the workflow level is very important. Currently, pull-requests: write is granted to the entire workflow. If gemini-code-review only needs read access to the PR content, it should explicitly request pull-requests: read (or contents: read) to follow the principle of least privilege. This is a high-impact follow-up item.
  • Template Injection Fix: The use of LABEL_JSON and EVENT_ACTION environment variables for jq processing is a good improvement.
  • Action Pinning: Both actions/checkout and sshnaidm/gemini-code-review-action are correctly pinned.

copy-to-rhisv.yml

  • Template Injection Fixes: The use of environment variables for registry and image names in the skopeo copy commands is a good security enhancement.
  • Action Pinning: redhat-actions/podman-login is correctly pinned.

Performance Optimizations

  • The changes are primarily security-focused and do not introduce or address significant performance bottlenecks. The impact on performance should be minimal.

Conclusion

This pull request is a strong positive change for the project's security. The implementation of action pinning, template injection prevention, and credential persistence control are critical and well-executed. The introduction of zizmor is also a valuable addition.

The main area for future improvement, as already identified in the TODO comments, is to refine the GitHub Actions token permissions to follow the principle of least privilege more strictly, especially for jobs that don't require write access.

Overall Recommendation: Approve with high confidence.

@openshift-ci openshift-ci bot added lgtm Indicates that a PR is ready to be merged. approved Indicates a PR has been approved by an approver from all required OWNERS files. labels Aug 4, 2025
@github-actions
Copy link

github-actions bot commented Aug 4, 2025

Code Review by Gemini

This pull request significantly improves the security posture of your GitHub Actions workflows, addressing several common attack vectors. The changes are well-aligned with the detailed commit message and demonstrate a strong commitment to security best practices.

Here's a breakdown of the review:

Overall Assessment

The changes are excellent and directly address the stated goals:

  • Template Injection Prevention: Successfully implemented by assigning GitHub Actions expressions to environment variables before use in shell scripts. This is a crucial improvement.
  • Action Pinning: All third-party actions are now pinned to specific Git SHAs, which is a critical security best practice to prevent supply chain attacks. The comments indicating the original tag are helpful for Dependabot.
  • Credential Persistence: persist-credentials: false has been added to all actions/checkout steps, preventing the GITHUB_TOKEN from being written to the .git/config file.
  • zizmor Integration: The new check-actions.yml workflow introduces static analysis for GitHub Actions, which is a proactive security measure. It's also implemented with minimal permissions (permissions: {}), which is excellent.
  • Excessive Token Permissions: The commit message explicitly states this is a follow-up, and the addition of TODO comments and zizmor: ignore[excessive-permissions] comments in the code acknowledges this. This is a good approach for incremental security improvements.

Detailed Feedback

Security Vulnerabilities & Best Practices

  1. Template Injection Fixes (add-release-info-to-pyxis.yml, build-main.yml, build-multiarch.yml, copy-to-rhisv.yml, code-review.yml):

    • Positive: The refactoring to assign complex expressions or sensitive inputs to environment variables (e.g., DATA_PAYLOAD, PYXIS_ENDPOINT, RELEASE_TAG, INPUT_NAME, DIGEST, SOURCE_IMAGE_REGISTRY) before using them in run steps is a robust defense against template injection. This ensures the shell correctly interprets the values rather than potentially executing malicious code embedded in the input.
    • Example: The change in add-release-info-to-pyxis.yml from curl ... -d '{"commit":"${{ inputs.commit }}"...}' to using a DATA_PAYLOAD environment variable is a perfect example of this mitigation.
  2. Action Pinning (All Workflows):

    • Positive: Every third-party action has been updated to use a full Git SHA-1 hash instead of a floating tag (e.g., actions/checkout@v4 to actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2). This is a critical security improvement that prevents an attacker from re-tagging an action to a malicious version. The comments indicating the original tag are very helpful for maintainability and Dependabot.
  3. Credential Persistence (actions/checkout in build-main.yml, build-release.yml, check-actions.yml, code-review.yml, go.yml, release-artifacts.yml):

    • Positive: The addition of with: persist-credentials: false to all actions/checkout steps is an excellent security hardening measure. It prevents the GITHUB_TOKEN from being stored in the .git/config file within the checked-out repository, reducing the risk of credential leakage if the repository is later uploaded as an artifact or compromised.
  4. Explicit Permissions (check-actions.yml):

    • Positive: The new check-actions.yml workflow correctly sets permissions: {} at the workflow level. This is a best practice for new workflows, ensuring that the GITHUB_TOKEN has no default permissions and jobs must explicitly request only what they need.
  5. Acknowledged Security Debt (All Workflows):

    • Positive: The TODO: Set explicit permissions for this job. comments and zizmor: ignore[excessive-permissions] annotations are well-placed. They clearly indicate that the issue of excessive token permissions is recognized and planned for future work, aligning with the commit message. This transparency is valuable.
    • Positive: The code-review.yml workflow correctly uses zizmor: ignore[dangerous-triggers] for pull_request_target. This trigger is inherently risky as it runs with base repository permissions on untrusted PRs, but it's often necessary for certain automation tasks. Acknowledging this risk and mitigating it with other measures (like persist-credentials: false and careful input handling) is good.

Performance Optimizations

  • The changes are primarily security-focused and do not introduce any significant performance optimizations or regressions. Pinning actions might slightly improve cache hit rates for action downloads, but the impact is likely negligible.

Idiomatic Go

  • This review focuses on GitHub Actions workflows (YAML), not Go code. Therefore, "Idiomatic Go" is not applicable here.

Minor Suggestions

  1. Consistency in Permission TODOs: While many jobs now have TODO: Set explicit permissions for this job. and zizmor: ignore[excessive-permissions], some jobs in add-release-info-to-pyxis.yml, build-multiarch.yml, copy-to-rhisv.yml, and release-artifacts.yml do not have these comments, even if their default permissions might be excessive. For consistency and to ensure these are tracked for future work, consider adding these comments to all jobs where explicit permissions are not yet defined.

Conclusion

This pull request represents a substantial and well-executed security improvement for your GitHub Actions workflows. The changes are thorough, correctly implemented, and demonstrate a proactive approach to supply chain security.

Approved.

@caxu-rh caxu-rh force-pushed the github-actions-hardening branch from 1dee373 to f495956 Compare August 18, 2025 18:12
@openshift-ci openshift-ci bot removed the lgtm Indicates that a PR is ready to be merged. label Aug 18, 2025
@caxu-rh caxu-rh force-pushed the github-actions-hardening branch from f495956 to 50ae9ce Compare August 18, 2025 18:14
@caxu-rh
Copy link
Contributor Author

caxu-rh commented Aug 18, 2025

Edited to add scanning with actionlint, which also runs shellcheck on inline scripts, to enforce best practices such as quoting environment variables, etc.

@dcibot
Copy link

dcibot commented Aug 18, 2025

@dcibot
Copy link

dcibot commented Aug 18, 2025

@caxu-rh caxu-rh force-pushed the github-actions-hardening branch from 50ae9ce to a18b9d2 Compare August 19, 2025 15:59
@acornett21
Copy link
Contributor

/lgtm

@openshift-ci openshift-ci bot added lgtm Indicates that a PR is ready to be merged. and removed lgtm Indicates that a PR is ready to be merged. labels Aug 19, 2025
@dcibot
Copy link

dcibot commented Aug 19, 2025

@dcibot
Copy link

dcibot commented Aug 19, 2025

@acornett21
Copy link
Contributor

/lgtm

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Aug 19, 2025
@openshift-merge-robot openshift-merge-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Sep 9, 2025
Copy link
Contributor

@bcrochet bcrochet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would like to see a final pass that all of the release tags for actions used are up-to-date. Otherwise, lgtm

Signed-off-by: Caleb Xu <caxu@redhat.com>
Signed-off-by: Caleb Xu <caxu@redhat.com>
@caxu-rh caxu-rh force-pushed the github-actions-hardening branch from a18b9d2 to fb1d072 Compare October 20, 2025 18:45
@openshift-ci openshift-ci bot removed the lgtm Indicates that a PR is ready to be merged. label Oct 20, 2025
@openshift-merge-robot openshift-merge-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Oct 20, 2025
@caxu-rh
Copy link
Contributor Author

caxu-rh commented Oct 20, 2025

Updated. Since the last time I visited this, Zizmor also added an audit on cooldown blocks in Dependabot config. This feature basically tells Dependabot to ignore new versions that are too new, which is a rough way of avoiding supply chain attacks. Zizmor audits the value and looks for at least 4 days or more in the config. I figure this is fine for us since:

  • We cut releases far less often than we merge Dependabot PRs, so waiting an extra few days/week for the next Dependabot run is probably not that big of deal
  • For high priority, urgent updates, we'd probably want to pick the update manually anyways (rather than waiting up to a week for the next Dependabot run)

More about the cooldown config in Dependabot, and more about the Zizmor audit.

Alternatively, we can also disable/ignore this particular audit if this seems unreasonable.

@dcibot
Copy link

dcibot commented Oct 20, 2025

@caxu-rh
Copy link
Contributor Author

caxu-rh commented Oct 21, 2025

/retest

Copy link
Contributor

@bcrochet bcrochet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/lgtm

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Oct 30, 2025
@openshift-ci
Copy link

openshift-ci bot commented Oct 30, 2025

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: acornett21, bcrochet, caxu-rh

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:
  • OWNERS [acornett21,bcrochet]

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@acornett21 acornett21 merged commit 883287b into redhat-openshift-ecosystem:main Oct 30, 2025
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants