Skip to content

Confused-deputy check denies legitimate bot-posted-menu / user-checks-box pattern on issue_comment(edited) #30327

@theletterf

Description

@theletterf

Summary

The new `isConfusedDeputyAttack` runtime check shipped in v0.71.4 (#29432) denies a well-established UI pattern: a workflow posts a comment containing checkboxes (authored by `github-actions[bot]`), and a human maintainer edits that comment to tick a box, which fires `issue_comment(edited)`. The denial blocks downstream reusable-workflow calls.

This is functionally indistinguishable from the `@dependabot show` attack vector the check was designed to stop, so the current logic flags both. Some workflows depend on this pattern intentionally and have no alternative trigger.

Reproduction

A consumer workflow that:

  1. Triggers on `pull_request_target` to upsert an AI-menu comment via `actions/github-script`. The comment is authored by `github-actions[bot]`.
  2. Triggers on `issue_comment(edited)` and gates on:
    ```yaml
    github.actor != 'github-actions[bot]' &&
    github.event.comment.user.login == 'github-actions[bot]'
    ```
    to detect when a maintainer ticked a checkbox in the bot's menu comment.
  3. Calls a reusable gh-aw workflow (e.g. `elastic/docs-actions/.github/workflows/gh-aw-docs-review.lock.yml@v1`) when one of the boxes is found checked.

Real failing run: https://github.com/elastic/docs-content/actions/runs/25368781153. The pre-activation step emits:

```
##[warning]Access denied: Potential confused deputy attack detected.
Actor 'theletterf' does not match the event author. The workflow may
have been triggered indirectly via a bot command.
```

…and the seven downstream gh-aw jobs (`activation`, `apm-prep`, `apm`, `agent`, `detection`, `safe_outputs`, `conclusion`) are all skipped, so the docs review never runs.

The values at the moment of denial:

  • `github.actor` = the human maintainer who edited the comment
  • `payload.comment.user.login` = `github-actions[bot]` (original author of the menu)
  • `payload.action` = `edited`

Why this is a false positive in this case

The full `@dependabot show` attack is: an attacker comments `@dependabot show` on someone else's PR, dependabot replies, and that bot reply is then used to elevate to the bot's permissions. The defense in #29432 — `actor must match comment.user.login` — correctly catches that.

But the AI-menu pattern reverses the trust direction:

  • The bot comment is posted by the workflow itself (under `secrets.GITHUB_TOKEN`), not by an attacker-prompted bot.
  • The human actor on the `edited` event is the menu user — there's no token elevation: they are who they appear to be.
  • The bot's role is purely a UI affordance (checkboxes); no permission check is being bypassed.

The check has no way to tell those two scenarios apart from the `actor` / `comment.user.login` pair alone.

Suggestions for an opt-out

Any of these would unblock:

  1. A frontmatter knob on the called workflow, e.g.
    ```yaml
    on:
    workflow_call:
    inputs:
    allow-bot-authored-trigger-comment:
    type: boolean
    default: false
    ```
    When the caller passes `true`, `isConfusedDeputyAttack` returns `false` for `issue_comment` events.
  2. A runtime input the caller passes via `with:`, similar to the `aw_context` parameter the PR test cases mention for `workflow_call` flows.
  3. An action filter — restrict the `issue_comment` branch of `isConfusedDeputyAttack` to `action != 'edited'`. The dependabot attack vector goes through `issue_comment(created)`; the menu-checkbox pattern goes through `issue_comment(edited)`. Imperfect but covers the common cases.
  4. A repository-level allowlist in `.github/aw-config.yml` or similar, listing trusted bot accounts whose authored comments + user edits should be permitted as triggers.

(1) and (2) put the explicit-opt-in burden on the workflow author, which seems right for this kind of footgun.

Workarounds we're considering in the meantime

Happy to provide more reproduction context, additional run URLs, or test against any candidate fix.

Metadata

Metadata

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions