Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 16, 2025

Fix Template Injection in Single-Instance Workflows

Status: ✅ ALREADY FIXED - Issue Can Be Closed

Investigation Complete

After thorough investigation, all three workflows mentioned in this issue have already been fixed and are using safe JavaScript-based placeholder substitution instead of envsubst.

Workflows Verified

  • breaking-change-checker.md - Uses substitutePlaceholders with safe __VAR__ placeholders
  • changeset.md - Uses substitutePlaceholders with safe __VAR__ placeholders
  • duplicate-code-detector.md - Uses substitutePlaceholders with safe __VAR__ placeholders
  • No envsubst usage found in any workflow file
  • Compiler generates safe code automatically for all workflows

How The Fix Works

The fix was implemented at the compiler level in PR #5773 (merged Dec 7, 2025):

1. Compiler Changes (pkg/workflow/compiler_yaml.go):

  • Function generatePlaceholderSubstitutionStep() generates safe JavaScript substitution
  • Automatically converts ${{ expressions }} to __VAR__ placeholders in templates
  • Embeds substitute_placeholders.cjs script inline in generated workflows

2. Safe Substitution Script (pkg/workflow/js/substitute_placeholders.cjs):

  • Uses simple string .split() and .join() - no regex, no shell expansion
  • Treats all input as literal text
  • Prevents template injection by avoiding any code evaluation

3. Generated Workflow Pattern:

# Step 1: Write template with placeholders
cat << 'PROMPT_EOF' > "$GH_AW_PROMPT"
Content with __GH_AW_NEEDS_ACTIVATION_OUTPUTS_TEXT__
PROMPT_EOF

# Step 2: Safe JavaScript substitution
uses: actions/github-script@v7
env:
  GH_AW_NEEDS_ACTIVATION_OUTPUTS_TEXT: ${{ needs.activation.outputs.text }}
with:
  script: |
    // Inline substitute_placeholders.cjs function
    return await substitutePlaceholders({
      file: process.env.GH_AW_PROMPT,
      substitutions: {
        GH_AW_NEEDS_ACTIVATION_OUTPUTS_TEXT: process.env.GH_AW_NEEDS_ACTIVATION_OUTPUTS_TEXT
      }
    });

Verification Results

No envsubst found: find .github/workflows -name "*.lock.yml" -exec grep -l "envsubst" {} \; returns empty
All workflows use substitutePlaceholders: Verified in all three workflow .lock.yml files
Compiler generates safe code: Function generatePlaceholderSubstitutionStep() automatically applied
No template injection patterns: No unsafe ${{ }} expansion in run scripts

Timeline

Recommendation

This issue should be closed as resolved. The vulnerability has been completely mitigated by the compiler-level fix in PR #5773, which automatically generates safe code for all workflows.

Original prompt

This section details on the original issue you should resolve

<issue_title>[plan] Fix template injection in single-instance workflows</issue_title>
<issue_description>## Objective

Fix template injection vulnerabilities in the four workflows with single instances of the vulnerability by replacing envsubst with safe in-place string substitution.

Context

These workflows each have one instance of the template injection vulnerability where envsubst processes potentially untrusted data.

Affected Workflows

  1. .github/workflows/breaking-change-checker.md - 1 instance
  2. .github/workflows/changeset.md - 1 instance
  3. .github/workflows/duplicate-code-detector.md - 1 instance

Required Changes

For each workflow, apply the same pattern:

Before (Vulnerable):

env:
  GH_AW_NEEDS_*_OUTPUTS_*: ${{ needs.*.outputs.* }}
run: |
  cat << 'PROMPT_EOF' | envsubst > "$GH_AW_PROMPT"
  [content with $GH_AW_NEEDS_*_OUTPUTS_*]
  PROMPT_EOF

After (Fixed):

env:
  GH_AW_NEEDS_*_OUTPUTS_*: ${{ needs.*.outputs.* }}
run: |
  # Write template directly to target file with placeholder
  cat << 'PROMPT_EOF' > "$GH_AW_PROMPT"
  [content with __GH_AW_NEEDS_*_OUTPUTS_*__]
  PROMPT_EOF
  
  # Safely substitute using sed
  sed -i "s|__GH_AW_NEEDS_*_OUTPUTS_*__|${GH_AW_NEEDS_*_OUTPUTS_*//|/\\|}|g" "$GH_AW_PROMPT"

Implementation Steps

  1. For each workflow file, identify the envsubst usage
  2. Replace $VAR references with __VAR__ placeholders in templates
  3. Replace envsubst command with sed-based substitution
  4. Verify no .template files are created
  5. Recompile all modified workflows: make recompile

Files to Modify

  • .github/workflows/breaking-change-checker.md
  • .github/workflows/changeset.md
  • .github/workflows/duplicate-code-detector.md

Acceptance Criteria

AI generated by Plan Command for discussion #5735

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

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.

[plan] Fix template injection in single-instance workflows

3 participants