Strips REVIEW_TOKEN (write:repository PAT) from the claude triage+review agents' environment via env -u REVIEW_TOKEN.
The step exports the token for its own curl/gitea_post calls, but that also left it in the agents' env — and those agents process attacker-controlled PR content, so a prompt-injected diff could read /proc/self/environ and exfiltrate the write-scoped PAT into the public review comment. The agents never call Gitea themselves (the shell does, via $AUTH), so the token isn't needed in their env.
Defence-in-depth alongside the existing settings.jsonRead(/proc/**) deny. Caught by the review bot; matches the fix on authentik #3 / HA #180 so all fleet copies stay identical.
Strips `REVIEW_TOKEN` (write:repository PAT) from the `claude` triage+review agents' environment via `env -u REVIEW_TOKEN`.
The step exports the token for its own `curl`/`gitea_post` calls, but that also left it in the agents' env — and those agents process attacker-controlled PR content, so a prompt-injected diff could read `/proc/self/environ` and exfiltrate the write-scoped PAT into the public review comment. The agents never call Gitea themselves (the shell does, via `$AUTH`), so the token isn't needed in their env.
Defence-in-depth alongside the existing `settings.json` `Read(/proc/**)` deny. Caught by the review bot; matches the fix on authentik #3 / HA #180 so all fleet copies stay identical.
The step exports REVIEW_TOKEN (write:repository PAT) for its own curl/gitea_post
calls, but that also placed it in the environment of the claude triage+review
agents, which process attacker-controlled PR content — a prompt-injected diff
could read /proc/self/environ and exfiltrate it into the public report. The
agents never call Gitea (the shell does, via $AUTH), so run them under
'env -u REVIEW_TOKEN'. Defence in depth alongside the settings.json /proc deny.
Caught by the review bot; matches the fix applied to the other fleet repos.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🤖Automated review — model claude-opus-4-8 (complexity: complex), commit a4836879a97e16958b59e834ae31674a51ab9ddc.
Advisory review by the review-bot pipeline. It never approves; a human merges. Push new commits to get a fresh review.
Summary
This PR prepends env -u REVIEW_TOKEN to the two claude agent invocations in .woodpecker/pr-review.yml, removing the write-scoped Gitea PAT from the
environment of the triage and review agents that process attacker-controlled PR
content. The change is minimal, correct, and closes a real credential-exfil path
as defence-in-depth. No blocking issues.
🔴 Blocking
None.
🟡 Suggestions
CLAUDE_CODE_OAUTH_TOKEN still remains in the agents' environment
(.woodpecker/pr-review.yml:65), since the claude CLI needs it to
authenticate — it can't be stripped the way REVIEW_TOKEN was. That token is a
secret too, and the same prompt-injection-reads-/proc/self/environ path
applies to it. The mitigation is the Read(//proc/**) deny in ci/agents/pr-review/settings.json:21, which the PR body correctly cites as
the other half of the defence. Worth a one-line comment noting that the OAuth
token is deliberately left in env and relies solely on the Read-sandbox, so a
future reader doesn't assume env -u covers both. Not required for this merge.
🟢 Nits
None.
Tests
No automated tests accompany this change, which is appropriate — this is a CI
YAML shell edit with no unit-testable surface. The correctness that matters is
behavioural and I verified it by reading the file:
env -u REVIEW_TOKEN unsets the variable only for the spawned claude
process, not the parent shell, so the shell's own AUTH header
(.woodpecker/pr-review.yml:126) and the gitea_post API calls
(:148–:156, :241) still have the token. Correct.
CLAUDE_CODE_OAUTH_TOKEN is untouched, so the agents can still authenticate to
Claude. Correct.
Both claude invocations (triage :205, review :217) receive the strip, so
neither agent sees the PAT. Complete.
Recommendation
Looks reasonable — no blocking issues; comments above are optional.
🤖 **Automated review** — model `claude-opus-4-8` (complexity: complex), commit `a4836879a97e16958b59e834ae31674a51ab9ddc`.
> Advisory review by the `review-bot` pipeline. It never approves; a human merges. Push new commits to get a fresh review.
---
## Summary
This PR prepends `env -u REVIEW_TOKEN` to the two `claude` agent invocations in
`.woodpecker/pr-review.yml`, removing the write-scoped Gitea PAT from the
environment of the triage and review agents that process attacker-controlled PR
content. The change is minimal, correct, and closes a real credential-exfil path
as defence-in-depth. No blocking issues.
## 🔴 Blocking
None.
## 🟡 Suggestions
- `CLAUDE_CODE_OAUTH_TOKEN` still remains in the agents' environment
(`.woodpecker/pr-review.yml:65`), since the `claude` CLI needs it to
authenticate — it can't be stripped the way `REVIEW_TOKEN` was. That token is a
secret too, and the same prompt-injection-reads-`/proc/self/environ` path
applies to it. The mitigation is the `Read(//proc/**)` deny in
`ci/agents/pr-review/settings.json:21`, which the PR body correctly cites as
the other half of the defence. Worth a one-line comment noting that the OAuth
token is *deliberately* left in env and relies solely on the Read-sandbox, so a
future reader doesn't assume `env -u` covers both. Not required for this merge.
## 🟢 Nits
None.
## Tests
No automated tests accompany this change, which is appropriate — this is a CI
YAML shell edit with no unit-testable surface. The correctness that matters is
behavioural and I verified it by reading the file:
- `env -u REVIEW_TOKEN` unsets the variable only for the spawned `claude`
process, not the parent shell, so the shell's own `AUTH` header
(`.woodpecker/pr-review.yml:126`) and the `gitea_post` API calls
(`:148`–`:156`, `:241`) still have the token. Correct.
- `CLAUDE_CODE_OAUTH_TOKEN` is untouched, so the agents can still authenticate to
Claude. Correct.
- Both `claude` invocations (triage `:205`, review `:217`) receive the strip, so
neither agent sees the PAT. Complete.
## Recommendation
Looks reasonable — no blocking issues; comments above are optional.
<!-- pr-review:sha=a4836879a97e16958b59e834ae31674a51ab9ddc -->
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.
Strips
REVIEW_TOKEN(write:repository PAT) from theclaudetriage+review agents' environment viaenv -u REVIEW_TOKEN.The step exports the token for its own
curl/gitea_postcalls, but that also left it in the agents' env — and those agents process attacker-controlled PR content, so a prompt-injected diff could read/proc/self/environand exfiltrate the write-scoped PAT into the public review comment. The agents never call Gitea themselves (the shell does, via$AUTH), so the token isn't needed in their env.Defence-in-depth alongside the existing
settings.jsonRead(/proc/**)deny. Caught by the review bot; matches the fix on authentik #3 / HA #180 so all fleet copies stay identical.🤖 Automated review — model
claude-opus-4-8(complexity: complex), commita4836879a97e16958b59e834ae31674a51ab9ddc.Summary
This PR prepends
env -u REVIEW_TOKENto the twoclaudeagent invocations in.woodpecker/pr-review.yml, removing the write-scoped Gitea PAT from theenvironment of the triage and review agents that process attacker-controlled PR
content. The change is minimal, correct, and closes a real credential-exfil path
as defence-in-depth. No blocking issues.
🔴 Blocking
None.
🟡 Suggestions
CLAUDE_CODE_OAUTH_TOKENstill remains in the agents' environment(
.woodpecker/pr-review.yml:65), since theclaudeCLI needs it toauthenticate — it can't be stripped the way
REVIEW_TOKENwas. That token is asecret too, and the same prompt-injection-reads-
/proc/self/environpathapplies to it. The mitigation is the
Read(//proc/**)deny inci/agents/pr-review/settings.json:21, which the PR body correctly cites asthe other half of the defence. Worth a one-line comment noting that the OAuth
token is deliberately left in env and relies solely on the Read-sandbox, so a
future reader doesn't assume
env -ucovers both. Not required for this merge.🟢 Nits
None.
Tests
No automated tests accompany this change, which is appropriate — this is a CI
YAML shell edit with no unit-testable surface. The correctness that matters is
behavioural and I verified it by reading the file:
env -u REVIEW_TOKENunsets the variable only for the spawnedclaudeprocess, not the parent shell, so the shell's own
AUTHheader(
.woodpecker/pr-review.yml:126) and thegitea_postAPI calls(
:148–:156,:241) still have the token. Correct.CLAUDE_CODE_OAUTH_TOKENis untouched, so the agents can still authenticate toClaude. Correct.
claudeinvocations (triage:205, review:217) receive the strip, soneither agent sees the PAT. Complete.
Recommendation
Looks reasonable — no blocking issues; comments above are optional.