Let anyone try to hijack it
This agent labels and comments on a public repository's issues, with a token that has write access. Anyone can try prompt injection. Every write it attempts is posted to Slack for approval. The prompt has no warnings, because the policy is enforced outside the model.
Requires a fine-grained GitHub token with write access to that repository's issues only, and a Slack app.
The files
Section titled “The files”mcp: github: url: https://api.githubcopilot.com/mcp/ headers: authorization: Bearer ${GITHUB_TOKEN} only: [list_issues, search_issues, issue_read, issue_write, add_issue_comment] gated: [issue_write, add_issue_comment]
channels: slack: type: slack token: ${SLACK_BOT_TOKEN} signing_secret: ${SLACK_SIGNING_SECRET} members: {U024BE7LH: user:default/@maria}
notify: targets: triage: {channel: slack, room: "#triage"}
roles: approver: rules: [{verbs: [read, events, decide], kinds: [agent], names: [issues]}]bindings: - {org: default, role: approver, subjects: [user:default/@maria]}- Both write tools are gated. After the agent reads an issue, gated calls need approval.
membersmaps a Slack ID touser:default/@maria. The binding allows that user to approve the agent's calls.
---description: Triages the issues anyone files on acme/widgets.model: anthropic:claude-sonnet-5tools: [github/*, files]context: [TRIAGE.md]triggers: - name: sweep every: 15m prompt: Triage the issues opened since your last sweep.policy: allow: [github/*, read_file, write_file(TRIAGE.md), edit_file(TRIAGE.md)] default: deny budget: {usd: 3.00, per: day, on_exhausted: deny}notify: triage---You triage the issues filed on github.com/acme/widgets.
For each issue opened since your last sweep, label it bug, feature or question, and comment on it:thank whoever filed it, and say what you would need from them to act on it. Keep the number of thelast issue you triaged in TRIAGE.md.default: denydenies every tool not matched byallow.- The budget caps the spend an attacker can cause.
Try it
Section titled “Try it”echo "$GITHUB_TOKEN" | wardrik vault put GITHUB_TOKEN --for headerecho "$SLACK_BOT_TOKEN" | wardrik vault put SLACK_BOT_TOKEN --for api_keyecho "$SLACK_SIGNING_SECRET" | wardrik vault put SLACK_SIGNING_SECRET --for signing_secretsystemctl --user restart wardrikwardrik agent show issuesOpen an issue with a prompt injection, then watch #triage:
issueswaits on a person to approvegithub__issue_write.{"issue_number":14,"labels":["bug"],"method":"update","owner":"acme","repo":"widgets"}
If an injection makes the model try to close every issue, each close is a pending call.
What it shows
Section titled “What it shows”- After content from outside, every gated call needs approval until
wardrik agent clear issues. See Content from outside. - Files written in the turn get the
outsidelabel, so notes can't pass an injection to a later turn. - The policy is defined outside the prompt, so no issue can change it. See Policy.
- Don't add
allow_after: {outside: [github/issue_write]}. The same tool both labels and closes.