Both the alert-triage-agent and issue-fix-agent steps hold Gitea write credentials in their environment (issue-fix holds a push token too), but neither passed --settings — so their Read tool was unrestricted. update-audit received a Read sandbox for exactly this reason (#197); these two never got the equivalent.
That left a complete exfil path:
Read /proc/self/environ → the token
Write → the agent's output file
the pipeline posts that output verbatim as a Gitea issue body / PR body — on a public repo
Adds the same deny-list update-audit uses (/proc, /root, /home, /etc, .git) to both agents and wires --settings into each invocation. The repo checkout, .ci-alert-monitor/ and /tmp/alert-fix/ stay readable, which is all either agent needs.
Defense-in-depth only. The root cause — CI pipelines holding an admin-owned token at all, and security_bot_token being reused outside the security pipeline — is tracked separately and fixed by the follow-up cutover to per-pipeline bot identities.
Both the `alert-triage-agent` and `issue-fix-agent` steps hold Gitea write credentials in their environment (issue-fix holds a push token too), but neither passed `--settings` — so their `Read` tool was unrestricted. `update-audit` received a Read sandbox for exactly this reason (#197); these two never got the equivalent.
That left a complete exfil path:
1. `Read /proc/self/environ` → the token
2. `Write` → the agent's output file
3. the pipeline posts that output verbatim as a Gitea issue body / PR body — on a **public** repo
Adds the same deny-list `update-audit` uses (`/proc`, `/root`, `/home`, `/etc`, `.git`) to both agents and wires `--settings` into each invocation. The repo checkout, `.ci-alert-monitor/` and `/tmp/alert-fix/` stay readable, which is all either agent needs.
**Defense-in-depth only.** The root cause — CI pipelines holding an admin-owned token at all, and `security_bot_token` being reused outside the security pipeline — is tracked separately and fixed by the follow-up cutover to per-pipeline bot identities.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Both agent steps hold Gitea write credentials in their environment
(issue-fix holds a push token too), but neither passed --settings, so
their Read tool was unrestricted — unlike update-audit, which got a
Read sandbox for exactly this reason (gitea issue #197).
That left a complete exfil path: Read /proc/self/environ yields the
token, Write puts it in the agent's output file, and the pipeline posts
that output verbatim as a Gitea issue body / PR body on a PUBLIC repo.
Add the same deny-list used by update-audit (/proc, /root, /home, /etc,
.git) to both agents and wire --settings into each invocation. The repo
checkout, .ci-alert-monitor/ and /tmp/alert-fix/ stay readable, which is
all either agent needs.
This is defense-in-depth only. The root cause — CI pipelines holding an
admin-owned token at all — is tracked separately.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Both the
alert-triage-agentandissue-fix-agentsteps hold Gitea write credentials in their environment (issue-fix holds a push token too), but neither passed--settings— so theirReadtool was unrestricted.update-auditreceived a Read sandbox for exactly this reason (#197); these two never got the equivalent.That left a complete exfil path:
Read /proc/self/environ→ the tokenWrite→ the agent's output fileAdds the same deny-list
update-audituses (/proc,/root,/home,/etc,.git) to both agents and wires--settingsinto each invocation. The repo checkout,.ci-alert-monitor/and/tmp/alert-fix/stay readable, which is all either agent needs.Defense-in-depth only. The root cause — CI pipelines holding an admin-owned token at all, and
security_bot_tokenbeing reused outside the security pipeline — is tracked separately and fixed by the follow-up cutover to per-pipeline bot identities.🤖 Generated with Claude Code