Summary
When a workflow's checkout.repository is set to a workflow_dispatch input expression (e.g. ${{ github.event.inputs.trigger_ref }}), the compiler-emitted "Build checkout manifest for safe-outputs handlers" step embeds that expression directly into a shell run: block. Starting with v0.78.3, the template-injection linter flags this as unsafe and gh aw compile fails.
The unsafe pattern is generated by gh-aw itself — there is no source-side workaround.
Affected versions
| Version |
Behavior |
| v0.78.0 – v0.78.2 |
✅ Compiles clean (manifest step not yet generated) |
| v0.78.3 |
❌ Compile fails — manifest step + tightened linter shipped together |
| v0.79.0, v0.79.1 |
❌ Same failure |
Reproduction
Minimal workflow:
---
on:
workflow_dispatch:
inputs:
trigger_ref:
type: string
required: true
engine: copilot
timeout-minutes: 5
checkout:
- repository: ${{ github.event.inputs.trigger_ref }}
current: true
safe-outputs:
noop:
report-as-issue: false
---
# Repro
Do nothing.
gh aw compile produces:
✗ template injection vulnerabilities detected in compiled workflow
repo='${{ github.event.inputs.trigger_ref }}'
Root cause
pkg/workflow/checkout_step_generator.go around line 122:
for _, e := range entries {
// Both repo and path are static at compile time. Use shell-quoted literals.
fmt.Fprintf(&sb, " repo=%s\n", shellSingleQuote(e.repository))
The comment assumes e.repository is always a static literal, but it's the raw string from frontmatter — which legitimately holds a ${{ … }} expression for dispatch-time targeting. shellSingleQuote wraps the expression in single quotes and the linter then sees an unsafe substitution inside run:.
Suggested directions (non-exhaustive)
- Detect
${{ in e.repository and emit the value via job-level env: referenced as $REPO_x in shell (the same pattern the codemod uses for user-authored steps), or
- Skip manifest emission for entries whose repository is dynamic and have the MCP server fall back to live
gh api resolution at runtime, or
- Resolve
default_branch in a downstream step that uses env: indirection instead of inline expression substitution.
Workarounds
None known on the consumer side — the unsafe substring is purely framework-generated. --strict=false does not bypass the template-injection linter. Affected users must remain on v0.78.2 or earlier, which means they cannot pick up the cross-org owner-derivation fix from #37976 that ships in v0.79.x.
Impact
This blocks adoption of v0.78.3+ for any workflow that uses dispatch-time trigger_ref patterns to target arbitrary repositories — a common pattern for centralized-ops architectures.
Summary
When a workflow's
checkout.repositoryis set to aworkflow_dispatchinput expression (e.g.${{ github.event.inputs.trigger_ref }}), the compiler-emitted "Build checkout manifest for safe-outputs handlers" step embeds that expression directly into a shellrun:block. Starting with v0.78.3, the template-injection linter flags this as unsafe andgh aw compilefails.The unsafe pattern is generated by gh-aw itself — there is no source-side workaround.
Affected versions
Reproduction
Minimal workflow:
gh aw compileproduces:Root cause
pkg/workflow/checkout_step_generator.goaround line 122:The comment assumes
e.repositoryis always a static literal, but it's the raw string from frontmatter — which legitimately holds a${{ … }}expression for dispatch-time targeting.shellSingleQuotewraps the expression in single quotes and the linter then sees an unsafe substitution insiderun:.Suggested directions (non-exhaustive)
${{ine.repositoryand emit the value via job-levelenv:referenced as$REPO_xin shell (the same pattern the codemod uses for user-authored steps), orgh apiresolution at runtime, ordefault_branchin a downstream step that usesenv:indirection instead of inline expression substitution.Workarounds
None known on the consumer side — the unsafe substring is purely framework-generated.
--strict=falsedoes not bypass the template-injection linter. Affected users must remain on v0.78.2 or earlier, which means they cannot pick up the cross-org owner-derivation fix from #37976 that ships in v0.79.x.Impact
This blocks adoption of v0.78.3+ for any workflow that uses dispatch-time
trigger_refpatterns to target arbitrary repositories — a common pattern for centralized-ops architectures.