Skip to content
GitHubGHSA-2cwf-x2h8-mqj5

gh-aw: unauthenticated prompt-injection to code execution in the shipped ai-moderator workflow

Medium6.5Published Aug 7, 2026

### Summary The shipped `ai-moderator.md` workflow, which runs on github/gh-aw itself, combines four settings that together hand an unauthenticated GitHub user code execution in the agent job. The agent job holds GITHUB_TOKEN and the engine API keys. The compiler emits no warning for this combination. This is live on github/gh-aw right now and reachable by any GitHub account with no special access. It is the most immediately exploitable of the issues I found in this review of gh-aw. I verified this against current `main` at commit `966ccb8` (2026-07-12). It was first verified at `bdfdb8e` (2026-06-24, ~v0.80.9); the intervening commits did not change any of the four ingredients. ### Details gh-aw treats issue/PR/comment content from arbitrary GitHub users as attacker-controlled, and its compiler normally env-indirects those expressions out of shell contexts. This workflow disables the controls that enforce that model. The four ingredients: 1. `roles: all` removes the activation gate. `needsRoleCheck` in `pkg/workflow/role_checks.go:348-353` returns false when roles is `["all"]`, so the compiled lock has no `check_membership` step. In the compiled `ai-moderator.lock.ym...

GitHub advisory

Affected versions

PackageAffectedFixed in
github/gh-aw
Product
< v0.86.1v0.86.1
Details and references

### Summary The shipped `ai-moderator.md` workflow, which runs on github/gh-aw itself, combines four settings that together hand an unauthenticated GitHub user code execution in the agent job. The agent job holds GITHUB_TOKEN and the engine API keys. The compiler emits no warning for this combination. This is live on github/gh-aw right now and reachable by any GitHub account with no special access. It is the most immediately exploitable of the issues I found in this review of gh-aw. I verified this against current `main` at commit `966ccb8` (2026-07-12). It was first verified at `bdfdb8e` (2026-06-24, ~v0.80.9); the intervening commits did not change any of the four ingredients. ### Details gh-aw treats issue/PR/comment content from arbitrary GitHub users as attacker-controlled, and its compiler normally env-indirects those expressions out of shell contexts. This workflow disables the controls that enforce that model. The four ingredients: 1. `roles: all` removes the activation gate. `needsRoleCheck` in `pkg/workflow/role_checks.go:348-353` returns false when roles is `["all"]`, so the compiled lock has no `check_membership` step. In the compiled `ai-moderator.lock.yml` the activation condition is just `rate_limit_ok && skip_roles_ok && skip_bots_ok`. The workflow triggers on `issues: [opened]`, `issue_comment: [created]`, and `pull_request: [opened]` with `forks: "*"`, all reachable by an external account. 2. `tools.github.min-integrity: none` defeats the author-association filter that public repos otherwise default to `approved` (`actions/setup/js/determine_automatic_lockdown.cjs:57`); a configured value is never overridden (`:61-67`). `threat-detection: false` removes the injection pre-screen. The prompt then instructs the agent to fetch raw content: "Use the GitHub MCP server tools to fetch the original context ... unsanitized content directly from GitHub API" and "Do NOT use the pre-sanitized text from the activation job". 3. `engine: codex` compiles to `codex exec --dangerously-bypass-approvals-and-sandbox` (`pkg/workflow/codex_engine.go:238`), so the agent auto-executes shell with no approval. The other auto-executing engines are equivalent: gemini emits `--yolo` (`pkg/workflow/gemini_engine.go:181`), copilot emits `--allow-all-tools` (`pkg/workflow/copilot_engine_tools.go:78`). The AWF firewall around the engine filters network egress only, not local execution. 4. An issue/PR/comment trigger reachable by arbitrary users (above). There is no compile-time diagnostic for open activation + `min-integrity: none` + an auto-executing engine. ### PoC I reproduced the full chain on my own repo on a real runner: an external issue activates the agent with no membership check, the raw issue body is built into the prompt, and the auto-approved agent runs shell via the engine and posts back to the issue. I used the gemini engine for the live run because I had a free key rather than codex credits; the mechanism is engine-independent, and the shipped ai-moderator uses codex. Markers were benign (`PWNED_*`). ### Impact Any GitHub account can drive shell execution inside the agent job on a repo running this pattern. Containment on most adopters: `--exclude-env` strips engine/MCP keys, the agent token is read-only, egress is allowlisted. The last step is XPIA (the model must follow the payload). Every control that would normally make that unreliable is disabled by this configuration, the payload surface is the whole body/diff, and the prompt instructs the model to trust raw content. CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:L/A:L (7.5). Up to 9.1 (Critical) where the agent has an arbitrary-shell tool. ### Suggested fix Fail the build, or emit a hard warning, when open activation is combined with `min-integrity: none`/`unapproved` and an auto-executing engine. Stop shipping samples that instruct th

CVSS 3.1
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:L/A:L
Severity from
GitHub (reviewed advisory)
Weakness
CWE-94, CWE-1188

More GitHub advisories

All GitHub

Critical advisories by email

Wednesdays: the week’s critical and high advisories in the AI and data stack, with the fixed versions. Only in weeks that have some.

Double opt-in. Unsubscribe any time.