Summary
The qlaude, qopilot, and qodex workflows explicitly disable XPIA (Cross-Prompt Injection Attack) protection via disable-xpia-prompt: true while simultaneously granting Bash tool access, including registry.npmjs.org in the firewall allowlist, and injecting user-controlled text verbatim into the agent's system prompt as "Triggering Content." The q-assistant.md shared component additionally instructs the agent to proactively fetch and process the content of an arbitrary referenced issue via issue_read MCP call. Threat detection runs post-agent and is non-blocking (GH_AW_DETECTION_CONTINUE_ON_ERROR: "true"). Together, these create a complete, unguarded path from a prompt-injection payload to npm install of an attacker-controlled package with lifecycle script execution at runner level. A two-hop variant requires zero attacker write access.
Affected Area
Agent tool-restriction and XPIA defense layer; affected files: qlaude.md, qopilot.md, qodex.md, shared/q-assistant.md, shared/disable-xpia-prompt.md, and their compiled lock files.
Reproduction Outline
Two-hop variant (zero attacker write access required):
- Attacker (any GitHub user) creates an issue in the repository with a prompt-injection payload in the body, e.g., an instruction to run
npm install <malicious-package>.
- A write-access user (legitimate) comments
/qlaude please review issue #<attacker-issue-number> on any issue.
- gh-aw activates the
qlaude workflow; compute_text.cjs sanitizes shell/template injection but does not neutralize prompt-injection instructions within the text.
- The agent job starts with XPIA protection disabled,
Bash listed in --allowed-tools, and registry.npmjs.org in the firewall domain allowlist.
- Following
q-assistant.md's built-in instruction, the agent fetches the attacker's issue via issue_read MCP call and processes the attacker-controlled content with no XPIA framing to distinguish adversarial instructions from legitimate ones.
- If the model follows the injected instruction, it calls
Bash to execute npm install <malicious-package>; lifecycle scripts run with runner-level permissions. The agent then creates a PR via the create-pull-request safe-output potentially modifying .github/workflows/ files.
Observed Behavior
No technical control blocks npm install once the model calls Bash. The soft instruction "Never execute untrusted code" in q-assistant.md is a model-level prompt guideline with no enforcement mechanism. Removing the XPIA protection prompt eliminates the primary framing that would otherwise alert the model it may be under injection. Threat detection runs after the agent job completes and cannot undo an already-executed npm install.
Expected Behavior
The combination of disable-xpia-prompt: true, Bash tool access, and package registry connectivity should be rejected at the configuration level, or threat detection should be a hard gate for any Bash-capable workflow. At minimum, documentation for disable-xpia-prompt should explicitly warn that combining it with shell/package-registry access removes the last technical control between a prompt-injection payload and arbitrary code execution.
Suggested mitigations (from static analysis):
- Remove
Bash from Q-workflow tool allowlists — workflow optimization does not require shell execution.
- Re-enable XPIA protection, or add explicit data-context framing (e.g., XML-tagged block) for content fetched via
issue_read.
- Remove
registry.npmjs.org from Q-workflow network allowlists if Bash is retained.
- Change
GH_AW_DETECTION_CONTINUE_ON_ERROR to "false" for Bash-capable workflows so a detection finding blocks safe-output dispatch.
- Restrict
q-assistant.md's issue-reading instruction to the triggering issue only, closing the two-hop attack surface.
Security Relevance
The two-hop variant reduces the attacker prerequisite from write access to zero — any GitHub user who can create an issue can plant the payload. Successful exploitation enables npm package lifecycle script execution with runner-level permissions, potential secret exposure from the runner environment, and PR-based workflow injection for persistence across future runs.
Additional Context
The disable-xpia-prompt: true feature is documented as deliberately disabling the default XPIA prompt, but no documentation warns that combining it with Bash tool access and package registry connectivity creates an unguarded supply-chain attack surface. If this combination is an intentional design decision (e.g., Q-workflows are meant for fully trusted operators only), that assumption should be explicitly documented and enforced — for example, by restricting the disable-xpia-prompt feature to configurations that do not include shell tools or unrestricted network access.
gh-aw version: v0.68.3
Original finding: https://github.com/githubnext/gh-aw-security/issues/1919
Generated by File Issue · ● 465.1K · ◷
Summary
The
qlaude,qopilot, andqodexworkflows explicitly disable XPIA (Cross-Prompt Injection Attack) protection viadisable-xpia-prompt: truewhile simultaneously grantingBashtool access, includingregistry.npmjs.orgin the firewall allowlist, and injecting user-controlled text verbatim into the agent's system prompt as "Triggering Content." Theq-assistant.mdshared component additionally instructs the agent to proactively fetch and process the content of an arbitrary referenced issue viaissue_readMCP call. Threat detection runs post-agent and is non-blocking (GH_AW_DETECTION_CONTINUE_ON_ERROR: "true"). Together, these create a complete, unguarded path from a prompt-injection payload tonpm installof an attacker-controlled package with lifecycle script execution at runner level. A two-hop variant requires zero attacker write access.Affected Area
Agent tool-restriction and XPIA defense layer; affected files:
qlaude.md,qopilot.md,qodex.md,shared/q-assistant.md,shared/disable-xpia-prompt.md, and their compiled lock files.Reproduction Outline
Two-hop variant (zero attacker write access required):
npm install <malicious-package>./qlaude please review issue #<attacker-issue-number>on any issue.qlaudeworkflow;compute_text.cjssanitizes shell/template injection but does not neutralize prompt-injection instructions within the text.Bashlisted in--allowed-tools, andregistry.npmjs.orgin the firewall domain allowlist.q-assistant.md's built-in instruction, the agent fetches the attacker's issue viaissue_readMCP call and processes the attacker-controlled content with no XPIA framing to distinguish adversarial instructions from legitimate ones.Bashto executenpm install <malicious-package>; lifecycle scripts run with runner-level permissions. The agent then creates a PR via thecreate-pull-requestsafe-output potentially modifying.github/workflows/files.Observed Behavior
No technical control blocks
npm installonce the model callsBash. The soft instruction "Never execute untrusted code" inq-assistant.mdis a model-level prompt guideline with no enforcement mechanism. Removing the XPIA protection prompt eliminates the primary framing that would otherwise alert the model it may be under injection. Threat detection runs after the agent job completes and cannot undo an already-executednpm install.Expected Behavior
The combination of
disable-xpia-prompt: true,Bashtool access, and package registry connectivity should be rejected at the configuration level, or threat detection should be a hard gate for any Bash-capable workflow. At minimum, documentation fordisable-xpia-promptshould explicitly warn that combining it with shell/package-registry access removes the last technical control between a prompt-injection payload and arbitrary code execution.Suggested mitigations (from static analysis):
Bashfrom Q-workflow tool allowlists — workflow optimization does not require shell execution.issue_read.registry.npmjs.orgfrom Q-workflow network allowlists ifBashis retained.GH_AW_DETECTION_CONTINUE_ON_ERRORto"false"for Bash-capable workflows so a detection finding blocks safe-output dispatch.q-assistant.md's issue-reading instruction to the triggering issue only, closing the two-hop attack surface.Security Relevance
The two-hop variant reduces the attacker prerequisite from write access to zero — any GitHub user who can create an issue can plant the payload. Successful exploitation enables npm package lifecycle script execution with runner-level permissions, potential secret exposure from the runner environment, and PR-based workflow injection for persistence across future runs.
Additional Context
The
disable-xpia-prompt: truefeature is documented as deliberately disabling the default XPIA prompt, but no documentation warns that combining it withBashtool access and package registry connectivity creates an unguarded supply-chain attack surface. If this combination is an intentional design decision (e.g., Q-workflows are meant for fully trusted operators only), that assumption should be explicitly documented and enforced — for example, by restricting thedisable-xpia-promptfeature to configurations that do not include shell tools or unrestricted network access.gh-aw version: v0.68.3
Original finding: https://github.com/githubnext/gh-aw-security/issues/1919