Skip to content

Defence in depth: gate a bot actor in the Claude lanes on the PR author's association #443

Closed

Description

@kyle-sexton

Summary

Follow-up to #441 / #442, which added cursor[bot] to allowed_bots in both Claude lanes.

allowed_bots admits an actor to a privileged run — this lane's CLAUDE_CODE_OAUTH_TOKEN plus the inline-comment tool's one-click-appliable suggestion capability. Trusting an entry therefore requires that an arbitrary commenter cannot drive that app.

For cursor[bot] that was verified as far as public documentation allows, and recorded in both lanes' security-model blocks:

  • Starting a Cursor cloud agent requires being "on a paid Cursor plan and have repository permissions" (docs).
  • Bugbot — the one Cursor path documented as running "for all contributors ... regardless of team membership" (docs) — is disabled for this org's account.
  • Empirically, cursor[bot] has authored zero PRs across the fleet; every observed action is a push to an operator-authored PR's branch.

Residual: Cursor states those as product prerequisites, not as a security boundary for the GitHub comment trigger. The trust therefore rests on vendor behaviour, not a contract.

Proposed guard

Gate a bot actor on the PR author's association rather than on the actor alone: when github.actor is a bot, additionally require github.event.pull_request.author_association to be OWNER, MEMBER, or COLLABORATOR.

The operator's real case passes (the human authors the PR; cursor[bot] pushes to its branch). A hypothetical stranger-instigated cursor[bot]-authored PR would not, since a GitHub App is not a repo collaborator.

Verification needed before implementing

  • Confirm the observed author_association values empirically for each admitted actor, including Dependabot's own PRs — Dependabot authors its PRs directly, so a naive guard could regress the Dependabot path this lane already depends on.
  • Decide where the guard lives: the existing job-level if chain, or a dedicated step, in both lanes and both attempts (main + retry).

Bounding note

This is defence in depth, not a gap that reopens the human-actor gate. cursor[bot] already holds contents: write org-wide, so an actor able to drive it could already push branches that run every same-repo workflow; allowed_bots is not the control protecting that.

Related

Follows #441. No linked issue closes this one.

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-triageNot yet classified. Floor until a type and one priority tier are set.

    Type

    No type

    Fields

    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