Skip to content

Harden workflows against script injection#9

Merged
jeremy merged 3 commits intomainfrom
prompt-injection
Mar 7, 2026
Merged

Harden workflows against script injection#9
jeremy merged 3 commits intomainfrom
prompt-injection

Conversation

@jeremy
Copy link
Copy Markdown
Member

@jeremy jeremy commented Mar 7, 2026

Summary

  • Fix script injection via AI model output in labeler workflow (use response-file, structured JSON output, env vars for PR numbers)
  • Fix $GITHUB_ENV injection in release changelog step (use file-based approach)
  • Remove secrets:inherit, add explicit secret declarations
  • Move ref names and commit SHAs out of shell interpolation
  • Add environment gate on sync-skills job
  • Narrow permissions from workflow-level to per-job
  • Apply all fixes to seed templates

Context

Security audit of GitHub Actions workflows identified script injection vectors where ${{ }} expressions are interpolated by the Actions runner before bash executes. This PR eliminates all identified injection paths in both the repo workflows and seed templates.

jeremy added 2 commits March 7, 2026 07:54
Use response-file instead of inline model output interpolation, pass PR
numbers through environment variables, and switch to structured JSON
output for the classifier prompt. Applied to both repo workflow and seed
template.
Replace $GITHUB_ENV injection vector in release changelog with file-based
approach. Remove secrets:inherit in favor of explicit secret declarations.
Move ref_name and commit SHA out of shell interpolation into environment
variables. Add environment gate on sync-skills job. Narrow permissions
from workflow-level to per-job. Apply all fixes to seed templates.
Copilot AI review requested due to automatic review settings March 7, 2026 15:55
@github-actions github-actions Bot added ci seed prompts bug Something isn't working labels Mar 7, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR systematically hardens GitHub Actions workflows against script injection vulnerabilities by moving all ${{ }} expression interpolations out of run: shell scripts and into env: blocks, switching AI model output to structured JSON format (with a response-file-based approach instead of writing to $GITHUB_ENV), narrowing permissions from workflow-level to per-job, replacing secrets: inherit with explicit secret declarations, and adding environment gates to sensitive jobs.

Changes:

  • Injection vector remediation: All ${{ }} expressions previously interpolated directly in run: steps are moved to env: variables, covering tokens, PR numbers, commit SHAs, ref names, run IDs, and AI response files across all workflows.
  • AI model output hardening: The classify-pr prompt now enforces a structured JSON schema response instead of a free-form single word, with file-based response passing instead of $GITHUB_ENV heredoc injection. GoReleaser changelog step likewise uses a file path output instead of $GITHUB_ENV.
  • Permissions and secrets scoping: Workflow-level permissions blocks are removed and replaced with per-job declarations; secrets: inherit is replaced with explicit secret passing.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
.github/workflows/release.yml Removed workflow-level permissions/secrets; moved ${{ github.sha }} and ref/changelog expressions to env: blocks; added environment: release to sync-skills; moved sync-skills env vars to env: block
.github/workflows/ai-labeler.yml Moved PR number and response-file references to env: blocks; replaced steps.classify.outputs.response with file-based response-file output
.github/prompts/classify-pr.prompt.yml Changed system prompt to request JSON response; added responseFormat with json_schema enforcement
seed/.github/workflows/test.yml Moved app token interpolation to env: block in all 7 "Configure git for private modules" steps
seed/.github/workflows/security.yml Added explicit secrets: block to workflow_call trigger; moved app token to env: block in gosec and codeql jobs
seed/.github/workflows/release.yml Removed workflow-level permissions; added per-job permissions; replaced secrets: inherit with explicit secret; moved all expression interpolations to env: blocks; split GoReleaser into install+run; replaced $GITHUB_ENV heredoc approach with file-path output
seed/.github/workflows/ai-labeler.yml Moved PR number and response-file references to env: blocks; replaced steps.classify.outputs.response with file-based approach
seed/.github/prompts/classify-pr.prompt.yml Same as the non-seed counterpart: JSON response format with json_schema schema

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/prompts/classify-pr.prompt.yml Outdated
Comment thread seed/.github/prompts/classify-pr.prompt.yml Outdated
…ssions, and changelog default

- Split label extraction into two lines so tr normalization always runs
- Standardize responseFormat to match detect-breaking.prompt.yml shape
- Bump maxCompletionTokens from 10 to 25 for JSON output headroom
- Restore top-level permissions so reusable security workflow gets security-events:write
- Default RELEASE_CHANGELOG to empty string so GoReleaser template doesn't fail on missing key
@jeremy jeremy merged commit a936893 into main Mar 7, 2026
18 checks passed
@jeremy jeremy deleted the prompt-injection branch March 7, 2026 19:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working ci prompts seed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants