You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Follow-up to #288. Same lane, different threat class — this one is about what reaches the AGENT, not what reaches the credentials.
The gap
claude-e2e-verify.yml's header enumerates its threats as trigger safety (:43-51), fork secret handling (:52-54), secret inheritance (:55), least privilege (:56-57), log hygiene (:58-60), template injection into run: steps (:61-64), and persisted-credential coexistence (:65-92).
Indirect prompt injection is absent from that list, and this lane feeds the agent more untrusted input than either review lane.
Three facts, all at c136b27:
The agent is pointed at PR-authored text by default.e2e-spec's default (:125-129) instructs: "Inspect the PR diff (use gh pr diff) to infer the primary user journeys this change affects". PR diff content is attacker-authored on any PR.
The agent is pointed at PR-authored rendered content. The whole lane exists to drive the app built from the PR head (:404, :414-416). Page text, DOM content, and console output all originate in the PR.
The agent holds credentials and has no tool restriction. The default claude_args is --model claude-sonnet-5 --max-turns 75 (:130-135) — no --allowedTools. Both review lanes constrain theirs (claude-review.yml:112-114, claude-security-review.yml:228-230 both pass --allowedTools "mcp__github_inline_comment__create_inline_comment"). The e2e agent runs with an authenticated gh (:365) and, per claude-e2e-verify: persisted-credential acceptance rests on a bound that does not hold — needs human re-ratification #288 item 4, the Claude App installation token in its environment.
So: untrusted text from two independent channels reaches an agent with shell access, an authenticated gh, a 75-turn budget, and no tool allowlist.
Why this lane is the sharp case
The review lanes have partial mitigation the e2e lane lacks entirely:
Both review lanes take exclude-comments-by-actor and default it to the Dependabot spellings — explicitly described in-source as "prompt-injection hygiene" (claude-review.yml:135-142, claude-security-review.yml:231-238). e2e has no such input; zero occurrences in the file.
Both review lanes constrain --allowedTools. e2e does not.
The review lanes read a diff. The e2e lane reads a diff and browses a live application rendering attacker-controlled content — a channel with no equivalent in the review lanes and no filtering at all.
What I am not claiming
I am not asserting a working exploit, and I have not attempted one. The claim is narrower and, I think, sufficient: this is a recognized threat class for agentic systems, the lane's own header inventories six other threat classes and reasons carefully about each, and this one does not appear. An acceptance review cannot weigh a risk that was never written down.
Nor am I claiming the missing --allowedTools is necessarily wrong — an e2e agent that must author and run Playwright scripts plausibly needs broad tool access, which is exactly why it deserves an explicit recorded decision rather than an unstated default.
Disposition
Fold into the same human re-ratification #288 requests, as a separate question from the credential residual: not "what can read the credentials" but "what can steer the agent that holds them". The two interact — a steered agent is a more capable attacker than a passive credential reader — but they need separate answers, and the current header answers neither.
Follow-up to #288. Same lane, different threat class — this one is about what reaches the AGENT, not what reaches the credentials.
The gap
claude-e2e-verify.yml's header enumerates its threats as trigger safety (:43-51), fork secret handling (:52-54), secret inheritance (:55), least privilege (:56-57), log hygiene (:58-60), template injection intorun:steps (:61-64), and persisted-credential coexistence (:65-92).Indirect prompt injection is absent from that list, and this lane feeds the agent more untrusted input than either review lane.
Three facts, all at
c136b27:e2e-spec's default (:125-129) instructs: "Inspect the PR diff (usegh pr diff) to infer the primary user journeys this change affects". PR diff content is attacker-authored on any PR.:404,:414-416). Page text, DOM content, and console output all originate in the PR.claude_argsis--model claude-sonnet-5 --max-turns 75(:130-135) — no--allowedTools. Both review lanes constrain theirs (claude-review.yml:112-114,claude-security-review.yml:228-230both pass--allowedTools "mcp__github_inline_comment__create_inline_comment"). The e2e agent runs with an authenticatedgh(:365) and, per claude-e2e-verify: persisted-credential acceptance rests on a bound that does not hold — needs human re-ratification #288 item 4, the Claude App installation token in its environment.So: untrusted text from two independent channels reaches an agent with shell access, an authenticated
gh, a 75-turn budget, and no tool allowlist.Why this lane is the sharp case
The review lanes have partial mitigation the e2e lane lacks entirely:
exclude-comments-by-actorand default it to the Dependabot spellings — explicitly described in-source as "prompt-injection hygiene" (claude-review.yml:135-142,claude-security-review.yml:231-238). e2e has no such input; zero occurrences in the file.--allowedTools. e2e does not.What I am not claiming
I am not asserting a working exploit, and I have not attempted one. The claim is narrower and, I think, sufficient: this is a recognized threat class for agentic systems, the lane's own header inventories six other threat classes and reasons carefully about each, and this one does not appear. An acceptance review cannot weigh a risk that was never written down.
Nor am I claiming the missing
--allowedToolsis necessarily wrong — an e2e agent that must author and run Playwright scripts plausibly needs broad tool access, which is exactly why it deserves an explicit recorded decision rather than an unstated default.Disposition
Fold into the same human re-ratification #288 requests, as a separate question from the credential residual: not "what can read the credentials" but "what can steer the agent that holds them". The two interact — a steered agent is a more capable attacker than a passive credential reader — but they need separate answers, and the current header answers neither.
Related
Follow-up to #288.
🤖 Generated with Claude Code
https://claude.ai/code/session_013pLW2dybov9xvTFtx48Ueb