Skip to content

fix(ci): prevent script injection in GitHub Actions workflows#559

Merged
aidandaly24 merged 1 commit into
mainfrom
fix/workflow-script-injection
Jun 30, 2026
Merged

fix(ci): prevent script injection in GitHub Actions workflows#559
aidandaly24 merged 1 commit into
mainfrom
fix/workflow-script-injection

Conversation

@aidandaly24

Copy link
Copy Markdown
Contributor

Description

Hardens our GitHub Actions workflows against script injection (the AppSec/ACAT "Script Injection in GitHub Actions workflows" finding class).

Several run: and actions/github-script steps interpolated GitHub context values directly into the script body via ${{ … }}. The Actions runner substitutes those before the shell/JS parses the line, so context data can execute as code. The fix follows GitHub's recommended pattern: bind each expression to an env: variable and reference the shell/JS variable instead (env: assignments are not an injection vector). No behavior changes.

Note: the release workflow that the AppSec scan originally flagged (release.yml) was already split into release-prepare.yml / release-publish.yml using the safe pattern; the remaining flagged instance on main lived on stale post-merge branches. This PR closes out the same vulnerability class everywhere else it still appears on main.

Files & what changed

  • breaking-change-check.ymlgithub.base_ref (a fork PR's source branch name) flowed into git fetch; now via env:. The github-script step reads steps.griffe.outputs.exit_code from process.env.
  • dependabot-auto-merge.ymlsteps.metadata.outputs.* (dependency names/versions/update-type) routed through env: in both echo steps.
  • integration-testing.yml / integration-testing-regression.ymlmatrix.extra-deps, matrix.path, matrix.ignore, matrix.group routed through env:. The pytest path/deps vars are intentionally left unquoted so they word-split into args exactly as before.
  • release-prepare.ymlgithub.ref in the "must run from main" error message routed through env:.

Testing

Workflow-only changes. Validated by:

  • YAML parses cleanly for all five workflows
  • Verified no ${{ }} expressions remain inside any run:/script: body across the entire .github/workflows/ tree
  • Behavior preserved (matrix word-splitting retained where intended)

Bind GitHub context values (github.ref, github.base_ref, step outputs,
and job matrix values) to env vars and reference them as shell/JS
variables instead of interpolating ${{ }} directly into run: and
github-script bodies. Inline expansion lets context data execute as
shell; routing through env: removes the injection surface.

github.base_ref in breaking-change-check.yml is the most notable case —
a fork PR's source branch name flows into 'git fetch'.

Matrix-derived test args (path/ignore/extra-deps) are kept unquoted
where word-splitting into multiple args is intended.

Files: release-prepare.yml, breaking-change-check.yml,
dependabot-auto-merge.yml, integration-testing.yml,
integration-testing-regression.yml
@aidandaly24 aidandaly24 requested a review from a team June 30, 2026 14:46
@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Jun 30, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation agentcore-devx-automation Bot removed the claude-security-reviewing Claude Code /security-review in progress label Jun 30, 2026
@Hweinstock

Copy link
Copy Markdown
Contributor

Unrelated test failure:

 FAILED tests_integ/evaluation/test_evaluation_passthrough.py::TestEvaluationClientPassthrough::test_list_evaluators_snake_case - botocore.exceptions.ClientError: An error occurred (ForbiddenException) when calling the ListEvaluators operation: Forbidden
FAILED tests_integ/evaluation/test_evaluation_passthrough.py::TestEvaluationClientPassthrough::test_get_builtin_evaluator - botocore.exceptions.ClientError: An error occurred (ForbiddenException) when calling the GetEvaluator operation: Forbidden
FAILED tests_integ/evaluation/test_evaluation_passthrough.py::TestEvaluationClientPassthrough::test_list_online_evaluation_configs_passthrough - botocore.exceptions.ClientError: An error occurred (ForbiddenException) when calling the ListOnlineEvaluationConfigs operation: Forbidden
FAILED tests_integ/evaluation/test_evaluation_passthrough.py::TestEvaluatorCrud::test_create_evaluator_and_wait - botocore.exceptions.ClientError: An error occurred (ForbiddenException) when calling the CreateEvaluator operation: Forbidden
ERROR tests_integ/evaluation/test_service_dataset_provider.py::TestDatasetManagementServiceProvider::test_get_predefined_dataset - botocore.exceptions.ClientError: An error occurred (ForbiddenException) when calling the CreateDataset operation: Forbidden
ERROR tests_integ/evaluation/test_service_dataset_provider.py::TestDatasetManagementServiceProvider::test_predefined_fields_preserved - botocore.exceptions.ClientError: An error occurred (ForbiddenException) when calling the CreateDataset operation: Forbidden
ERROR tests_integ/evaluation/test_service_dataset_provider.py::TestDatasetManagementServiceProvider::test_get_predefined_with_version - botocore.exceptions.ClientError: An error occurred (ForbiddenException) when calling the CreateDataset operation: Forbidden
ERROR tests_integ/evaluation/test_service_dataset_provider.py::TestDatasetManagementServiceProvider::test_get_synthetic_dataset - botocore.exceptions.ClientError: An error occurred (ForbiddenException) when calling the CreateDataset operation: Forbidden

@aidandaly24 aidandaly24 merged commit c771470 into main Jun 30, 2026
30 of 32 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants