Skip to content

Harden workflows against script injection#16

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

Harden workflows against script injection#16
jeremy merged 4 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)
  • Move ref names out of shell interpolation in release workflow
  • Narrow permissions from workflow-level to per-job
  • Pin all actions from mutable tags to immutable SHA commits

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 and pins every action reference to an immutable SHA.


Summary by cubic

Hardened all GitHub Actions workflows to block script injection and reduce supply‑chain risk. Model output is read from strict JSON response files, risky shell interpolation is removed, permissions are scoped, and every action is pinned to a SHA.

  • Bug Fixes

    • ai-labeler: move PR number to env; switch to response-file + strict json_schema; bump token limit; split jq extraction from normalization; validate labels before applying.
    • release: replace $GITHUB_ENV heredoc with file-based changelog via GITHUB_OUTPUT; default RELEASE_CHANGELOG to empty; strip code fences; move ref_name/run_id to env.
  • Refactors

    • Scope permissions per job (add models:read where needed) and restore security-events:write for security tooling.
    • Split GoReleaser install from execution; pass changelog via env instead of action input.
    • Pin all actions across ci, test, security, dependabot, and release to immutable SHAs with version comments.

Written for commit 87e1fb4. Summary will update on new commits.

Copilot AI review requested due to automatic review settings March 7, 2026 15:55
@github-actions github-actions bot added the bug Something isn't working label Mar 7, 2026
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name=".github/workflows/ai-labeler.yml">

<violation number="1" location=".github/workflows/ai-labeler.yml:83">
P1: Shell operator precedence bug: `tr '[:upper:]' '[:lower:]'` only runs in the fallback (jq-failure) branch. When jq succeeds, the label is not lowercased, so a model response like `{"label": "Bug"}` will hit the `*) ... skipping` case and silently do nothing.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Copy Markdown
Contributor

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

Hardens GitHub Actions workflows against script/env injection by eliminating direct ${{ }} interpolation inside shell scripts, switching to response-file / structured outputs for AI steps, tightening permissions, and SHA-pinning action references.

Changes:

  • SHA-pin all GitHub Actions used across CI/security/release/labeler workflows.
  • Update AI labeler + prompts to consume model output via response files (preferring structured JSON) rather than inline outputs.
  • Refactor release workflow to avoid $GITHUB_ENV injection and move permissions from workflow-level to per-job.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
.github/workflows/test.yml Pins checkout, setup-go, golangci-lint-action to SHAs.
.github/workflows/security.yml Pins actions to SHAs (checkout, CodeQL SARIF upload, dependency review, setup-go).
.github/workflows/release.yml Moves permissions to jobs, pins actions, and switches changelog propagation away from $GITHUB_ENV; reduces expression interpolation in shell.
.github/workflows/dependabot-auto-merge.yml Pins dependabot/fetch-metadata to a SHA.
.github/workflows/ci.yml Pins actions to SHAs across CI jobs.
.github/workflows/ai-labeler.yml Uses PR number via env and reads AI output from response files (jq) instead of inline string outputs.
.github/prompts/classify-pr.prompt.yml Switches classifier prompt to JSON output and adds a JSON-schema response format.

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

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0275c9db53

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

jeremy added 4 commits March 7, 2026 11:38
Move PR number from ${{ }} interpolation to env vars to prevent
script injection. Use response-file instead of inline response
output and add structured JSON schema to the classifier prompt
so the model output is machine-parseable without shell expansion.
Replace $GITHUB_ENV heredoc with file-based changelog passing via
GITHUB_OUTPUT to eliminate the injection surface from AI-generated
content. Move ref_name and run_id out of ${{ }} shell interpolation
into env vars. Split GoReleaser install from execution so the
changelog can be passed through the environment rather than through
action inputs. Narrow permissions from workflow-level to per-job.
Replace mutable @vn tags with full SHA pins across ci, test,
security, and dependabot-auto-merge workflows. Each pin includes
a version comment for auditability.
…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
Copilot AI review requested due to automatic review settings March 7, 2026 19:38
@jeremy jeremy force-pushed the prompt-injection branch from c821af0 to 87e1fb4 Compare March 7, 2026 19:38
Copy link
Copy Markdown
Contributor

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

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.


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

@jeremy jeremy merged commit c855afc into main Mar 7, 2026
24 checks passed
@jeremy jeremy deleted the prompt-injection branch March 7, 2026 19:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants