ci: harden GitHub Actions workflows (injection, pinning, least-privilege) - #92
Merged
Merged
Conversation
…ege) Behavior-preserving security hardening of the CI/QA/docs workflows. No functional change: every edited step keeps identical inputs, outputs and runtime behavior. Pins resolve to the exact SHA/digest already in use. Template-injection hardening (move config/expression values out of run:/JS splices into env: and reference $VARS, so PR-editable github_config.yml and step outputs can no longer break into the runner shell): - code-maven_java-QA_e2e_karate.yml: app-config, start-java-app, mvn-clean-verify, stop-java-app and generate-jacoco-report steps. - actions/test-results-verification/action.yml: run: step and the github-script body (now uses process.env.*). Command-injection removal: - test-results-summary.sh: drop eval; dispatch the validated parser function directly. - e2e_karate: replace `eval "$APP_HEALTH_CHECK_CMD"` with a direct curl. TLS: remove `curl -k` on the JaCoCo agent/CLI downloads (a MITM of the -javaagent JAR is code execution in CI). Supply-chain pinning: - asdf-vm/actions/install@v4 -> @b7bcd026f18772e44fe1026d729e1611cc435d47 - yuzutech/kroki -> @sha256:6980bfb218b48b74ea14b888d9c7e8c032d1cb6325f3292277abdf62483abd9d GITHUB_ENV heredoc: random delimiter (openssl rand) so untrusted .tool-versions content cannot forge the terminator and inject env vars. Least-privilege: add `permissions: contents: read` to the four QA workflows and docs-verify (all self-validated by this PR's own CI); add `persist-credentials: false` to their checkouts. Remove superfluous GPG/git-credential setup from docs jobs that never sign or push (docs-verify, docs-publish, docs-build_snapshot). Signed-off-by: Ivan Alvarez Sabin <ivanasabi@ext.inditex.com>
ivanasabi
force-pushed
the
security/harden-github-actions-workflows
branch
from
August 26, 2026 11:42
984b228 to
71ba39b
Compare
…workflows Clears the CodeQL 'Workflow does not contain permissions' alerts on the two docs workflows that still lacked a permissions block. Behavior-preserving: no step inputs, outputs or runtime behavior change; each job gets only the scopes it actually uses. docs-build_snapshot.yml: - check-triggered-release: contents:read + pull-requests:read (reads the commit and its associated PR labels via the API; no writes). - build-snapshot: contents:read + actions:write (clones with persist-credentials:false, then dispatches docs-publish via the default token -> workflow-dispatch needs actions:write). docs-release.yml: - dispatch: actions:write (only re-dispatches this workflow via the default token; no checkout). - release: contents:read (every git push, tag, PR and dispatch uses the App token from steps.app-token; the default token only clones the repo). docs-publish.yml already ships a top-level permissions block and is unchanged. Signed-off-by: Ivan Alvarez Sabin <ivanasabi@ext.inditex.com>
|
ivanasabi
marked this pull request as ready for review
August 26, 2026 12:21
marianoao
approved these changes
Aug 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



What & why
Behavior-preserving security hardening of the CI / QA / docs GitHub Actions workflows, from a read-only audit (
gha-security-review+zizmor+ci-secure). No functional change: every edited step keeps identical inputs, outputs, and runtime behavior; all pins resolve to the exact SHA/digest already in use. Net line count is negative because superfluous GPG blocks were removed.Scope is deliberately limited to code-level YAML fixes. It excludes anything requiring GitHub org/repo settings, the docs-release App-token scope (WF-SEC-011), and known-latent correctness items flagged for separate follow-up — those are out of scope for a behavior-preserving PR.
Changes
Template-injection hardening
Move PR-influenced values (config from
github_config.yml, step outputs) out ofrun:/github-script${{ }}splices into step-levelenv:, referenced via$VARS/process.env.*. A fork PR editinggithub_config.ymlcan no longer break out of the interpolation into the runner shell.code-maven_java-QA_e2e_karate.yml:app-config,start-java-app,mvn-clean-verify,stop-java-app,generate-jacoco-report.actions/test-results-verification/action.yml:run:step + thegithub-scriptbody.Command-injection removal
test-results-summary.sh: dropeval; call the already-validated parser function directly (RESULTS_TYPEis validated against an existing parser file before use).e2e_karate: replaceeval "$APP_HEALTH_CHECK_CMD"with a directcurlinvocation.TLS
curl -kfrom the JaCoCo agent/CLI downloads. A MITM of the downloaded-javaagentJAR would be code execution inside CI.Supply-chain pinning (third-party actions/images → immutable refs)
asdf-vm/actions/install@v4→@b7bcd026f18772e44fe1026d729e1611cc435d47 # v4yuzutech/kroki→@sha256:6980bfb218b48b74ea14b888d9c7e8c032d1cb6325f3292277abdf62483abd9dGITHUB_ENVheredoc injectionopenssl rand -hex 16) so untrusted.tool-versionscontent cannot forge the terminator and inject arbitrary env vars.Least-privilege
permissions: contents: readon the four QA workflows +docs-verify(each self-validated by this PR's ownpull_requestCI).persist-credentials: falseon their checkouts.Dead credential setup
~/.git-credentialssetup from docs jobs that never sign or push (docs-verify,docs-publish,docs-build_snapshot).Validation
yaml.safe_load);test-results-summary.shpassesbash -n.actionlintintroduces no new errors. The only delta is +8SC2086info (word-splitting) notices ine2e_karate— these are shellcheck gaining visibility into pre-existing unquoted usages ($MVN_PROPERTIES,$START_APP_CMD,$JACOCO_CLI_REPORT_OPTIONSare intentional, load-bearing word-splits;$JACOCO_VERSION/$APP_LOG_FILE/$APP_PIDare trusted values). No assignment I added is unquoted, so runtime word-splitting is unchanged, and env-binding neutralizes injection regardless of downstream quoting (shell variable expansion does not re-parse;/$()/|).Reviewer note
This PR edits workflow files that run under
pull_request, so its own CI validates the changed workflows from the PR merge commit — the checks on this PR are the test of these edits. Opened as a draft for review.