Skip to content

How to Auto-Approve Pull Requests in GitHub Safely

Auto-approve GitHub pull requests with gh, hmarr/auto-approve-action or Dependabot workflows, and avoid the pull_request_target and CODEOWNERS traps.

Published 8 min readBy the Warpway team

To auto-approve pull requests in GitHub, run a workflow that submits an approving review with gh pr review --approve or an action such as hmarr/auto-approve-action. If the workflow approves with the default GITHUB_TOKEN, also turn on Allow GitHub Actions to create and approve pull requests in the repository's Actions settings. The review comes from github-actions[bot] unless you pass a token for another account. Whether the setup is safe depends on two things: the condition that picks which pull requests get approved, and whether the approval still applies after the next push.

Before you start: the setting and who approves

GitHub stops workflows from approving pull requests with GITHUB_TOKEN unless you allow it. A workflow that approves with another account's token doesn't need the setting. Go to Settings → Actions → General, find Workflow permissions, and check Allow GitHub Actions to create and approve pull requests. GitHub's documentation says new repositories in a personal account start with this off. New repositories in an organization inherit the organization's setting.

Three GitHub rules apply to every option below:

  • Who approves. With the default GITHUB_TOKEN, the approval comes from github-actions[bot]. To approve as a different account, pass that account's token.
  • Authors can't approve their own pull requests. GitHub states that "pull request authors cannot approve their own pull requests." A token that belongs to the author won't work.
  • Only certain approvals count. For protected branches, required approvals must come from reviewers with write permission. A code-owner requirement is met only when a code owner approves.

Option 1: gh pr review --approve

The GitHub CLI approves a pull request by number, URL or branch:

bash
gh pr review 123 --approve --body "Docs-only change, auto-approved"

With no argument, it reviews the pull request for the current branch (manual). In a workflow, set GH_TOKEN to ${{ secrets.GITHUB_TOKEN }} and the same command approves as github-actions[bot]. The command checks nothing on its own; your script decides when to run it.

Option 2: Dependabot updates with fetch-metadata

GitHub's Dependabot automation docs combine dependabot/fetch-metadata, which outputs the update type and dependency names, with gh pr review --approve. This version approves only patch updates:

yaml
name: Dependabot auto-approve
on: pull_request

permissions:
  pull-requests: write

jobs:
  dependabot:
    runs-on: ubuntu-latest
    if: github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'owner/my_repo'
    steps:
      - name: Dependabot metadata
        id: metadata
        # GitHub's example pins this action to a commit SHA
        uses: dependabot/fetch-metadata@d7267f607e9d3fb96fc2fbe83e0af444713e90b7
        with:
          github-token: "${{ secrets.GITHUB_TOKEN }}"
      - name: Approve patch updates
        if: steps.metadata.outputs.update-type == 'version-update:semver-patch'
        run: gh pr review --approve "$PR_URL"
        env:
          PR_URL: ${{ github.event.pull_request.html_url }}
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

GitHub's own example approves every Dependabot pull request. It puts the condition, patch updates of a named dependency, on the merge step of a separate auto-merge workflow (gh pr merge --auto --merge "$PR_URL", which also needs contents: write). Putting a patch-only condition on the approval, as above, means a person still reviews minor and major bumps.

The same page has two more notes:

  • Dependabot-triggered runs read Dependabot secrets, not Actions secrets.
  • If you auto-merge, turn on Require status checks to pass before merging so the merge waits for CI.

Option 3: hmarr/auto-approve-action

hmarr/auto-approve-action approves the pull request that triggered the run. Its README describes it as a way to let selected pull requests, such as Dependabot's, past a rule that blocks merging without approval. It recommends v4, because earlier versions use deprecated Node.js:

yaml
name: Auto-approve
on: pull_request_target

jobs:
  approve:
    if: github.event.pull_request.user.login == 'dependabot[bot]'
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - uses: hmarr/auto-approve-action@v4
        with:
          review-message: "Auto-approved Dependabot update"

The README's examples check github.actor. The example above checks the pull request author instead, the way GitHub's Dependabot example does.

The action has three inputs:

  • github-token: a personal access token, to approve as another user. A fine-grained token needs Pull requests read/write and Metadata read. A classic token needs repo.
  • pull-request-number: needed for runs that aren't triggered by a pull request, such as workflow_dispatch.
  • review-message: optional text for the review.

The action checks no conditions itself, so your if: line is the whole policy. Also note that the README uses pull_request_target, which has security consequences covered below.

Option 4: github/privileged-requester

github/privileged-requester approves pull requests from accounts listed in config/privileged-requester.yaml on the default branch:

yaml
requesters:
  dependabot[bot]:
    labels:
      - dependencies
      - github_actions

It includes checks that the other options leave to you. By default:

  • checkCommits requires every commit to come from the listed requester.
  • checkLabels requires the pull request's labels to match the config.
  • checkDiff requires the diff to contain only removals. Confirm that this default fits the pull requests you want approved.

commitVerification can also require signed, verified commits.

Check the project's status before you adopt it. The repository page shows it was archived on November 27, 2025, so it is read-only and gets no fixes.

The options side by side

OptionApproves asConditions it checksNotes
gh pr review --approveThe token's ownerNone; your script decidesWorks in any workflow or terminal
Dependabot + fetch-metadatagithub-actions[bot]Update type, dependency names and typeGitHub's documented pattern
hmarr/auto-approve-action@v4github-actions[bot] or a token's userNone; your if: decidesREADME examples use pull_request_target
github/privileged-requestergithub-actions[bot] or a bot tokenRequester list, commit authors, removals-only diff, labels, signed commitsArchived November 2025
Warpway Auto-approveThe Warpway GitHub AppReview results, CI, paths, categories, size, authors, sign-offs, exact commitTeam plan; an Owner turns it on

Pitfalls that turn auto-approval into a bypass

pull_request_target runs with write access and secrets

pull_request_target runs the workflow from the base repository's default branch, not from the pull request. GitHub Security Lab notes that it gets a read/write repository token and the repository's secrets (Preventing pwn requests). GitHub's events reference says: "Avoid using this event if you need to build or run code from the pull request."

An approve-only job that never checks out the pull request is a reasonable use of it. It also has an advantage: the pull request can't edit the workflow that judges it. The danger starts when the job checks out the pull request's code, or runs npm install or a test script, to decide whether to approve. Security Lab points out that install hooks alone can run attacker code while the write token is in memory. If the decision depends on running the pull request's code, run that code in an unprivileged pull_request workflow, and treat its output as untrusted.

A pull request can rewrite its own approval rule

pull_request has the opposite trade-off: it runs the workflow file from the pull request's merge commit. Pull requests from forks get a read-only token and can't approve anything. A branch pushed to the same repository can, whether a teammate or a coding agent with write access pushed it. That branch can change the if: line, and the edited workflow is the one that runs.

To prevent this, add .github/workflows/ to CODEOWNERS and turn on Require review from Code Owners. A bot's approval doesn't meet that requirement, so a pull request that edits the workflow still needs a person.

Bot approvals don't satisfy CODEOWNERS

Code owners are users, teams and email addresses with write permission. A github-actions[bot] approval therefore doesn't count on paths that need a code owner's review.

The hmarr README's fix is a token for a user listed as a code owner, ideally a dedicated bot user in the team that owns the code. That works, but the scope is wide: the account can then meet code-owner review on everything the team owns, for any pull request your condition lets through.

Approvals outlive the commit they were given for

A pull request stays approved when new commits are pushed. Turn on Dismiss stale pull request approvals when new commits are pushed. With that setting and required reviews both on, a push that changes the code dismisses the approval.

The workflow then runs again on synchronize and approves again if its condition still holds. A condition that doesn't depend on the code, such as a label added earlier, carries over to code nobody has seen. Security Lab calls label gating only a temporary fix for this reason.

Checking the author isn't checking the commits

github.event.pull_request.user.login == 'dependabot[bot]' tells you who opened the pull request. It is still true after someone else pushes a commit to the Dependabot branch, so the workflow approves that commit too. privileged-requester's checkCommits exists for this case. With the other options, add your own commit-author check or limit who can push to those branches.

Condition-based approval with Warpway's Auto-approve trust level

The workflows above decide from metadata: author, labels and update type. Warpway decides from its review results for the exact commit. Auto-approve is the top of its trust levels (level 4), and it is off by default. To use it, you need:

  • the Team plan;
  • an Owner to turn on auto-approval for the organization and for the repository;
  • the repository at trust level 4;
  • auto_approve.enabled: true in policy.

Here is a Dependabot policy. Unlike Option 2, it has no update-type condition; it limits approval by file count, categories and CI instead:

yaml
version: 1
auto_approve:
  enabled: true
  dependabot_only: true
  max_files: 5
  excluded_categories:
    - auth
    - migration
  required_ci_checks:
    - build
    - unit-tests

Right before approving, code checks every condition in Auto-approval against the current state. Warpway never approves because a model reported high confidence. The conditions include:

  • the pull request's head commit is the commit Warpway reviewed, under the policy currently in effect;
  • every required lens is Cleared and none is Incomplete;
  • no required human task is open, and no blocking-severity finding is open;
  • each configured CI check concluded success (neutral and skipped don't count), and no other check is failing or still running;
  • the change avoids excluded_paths and excluded_categories. Path rules fail if Warpway couldn't get the full list of changed files;
  • required sign-offs are present, and optional rules such as max_changed_lines or docs_tests_only pass.

One of the pitfalls above is handled by design: the policy comes from the base branch's .warpway.yml, so a pull request can't weaken the policy used to approve it (configuration).

Separately, if a later investigation demonstrates a material defect, Warpway withdraws its own approval of that exact head commit. It never dismisses a person's review. If GitHub's protected-review permissions block the withdrawal, the dashboard and check say a repository administrator must dismiss it.

There are limits. Warpway approves but never merges. Your GitHub rules decide whether its approval counts toward required approvals, and it works with GitHub only. Its docs recommend turning on dismiss-stale-approvals so an approval never outlives its commit. The app isn't a user or team in CODEOWNERS, so either add code-owned paths to excluded_paths or expect a person to review them. For a comparison with other review tools that approve, see AI code review tools that approve pull requests.

A short checklist

  1. Allow Actions to approve only in repositories that need it.
  2. Write the condition first, and keep it to narrow classes such as Dependabot patch updates or docs-only changes.
  3. Never check out or run the pull request's code in a pull_request_target job.
  4. Add .github/workflows/ to CODEOWNERS and require code-owner review.
  5. Turn on dismiss-stale-approvals, and base conditions on the code at the head commit.
  6. Require status checks before any auto-merge, and see merge gating if a review check should block merges too.

Frequently asked questions

Does an approval from github-actions[bot] count toward required approvals?

GitHub counts approvals from reviewers with write access toward a required-approvals rule, and the hmarr/auto-approve-action README presents the action as a way to get selected pull requests past that rule. It does not meet Require review from Code Owners on owned paths, because code owners are users, teams and email addresses. Try your exact ruleset in a test repository before you rely on it.

Can I auto-approve my own pull requests?

Not with your own account. GitHub's documentation says pull request authors cannot approve their own pull requests, so a personal access token that belongs to the author fails. A token for a different account can approve. Then your approval requirement is being met by automation instead of a second person, so keep the condition narrow.

Why does my auto-approve workflow fail on Dependabot pull requests?

GitHub treats workflows triggered by Dependabot pull requests as if they came from a fork, and those runs read Dependabot secrets, not Actions secrets. Grant pull-requests: write in the workflow's permissions block, as GitHub's example does, and store any token you need as a Dependabot secret. The hmarr README suggests pull_request_target when a personal access token fails on Dependabot pull requests. If you switch, do not check out the pull request's code.

Can an auto-approve workflow add the pull request to a merge queue?

Not with the default token. GitHub's Dependabot automation docs say GITHUB_TOKEN cannot add pull requests to a merge queue, and they recommend a personal access token or GitHub App token with merge permission for the gh pr merge step.

Does Warpway merge a pull request after it auto-approves it?

No. Warpway can submit an approving review but has no permission to merge. If you want approved pull requests to merge on their own, use GitHub's auto-merge. Your GitHub branch rules decide whether Warpway's approval counts toward required approvals.

Sources

  1. hmarr/auto-approve-action (GitHub)
  2. github/privileged-requester (GitHub)
  3. Automating Dependabot with GitHub Actions - GitHub Docs
  4. Managing GitHub Actions settings for a repository - GitHub Docs
  5. About protected branches - GitHub Docs
  6. Events that trigger workflows - GitHub Docs
  7. About code owners - GitHub Docs
  8. Approving a pull request with required reviews - GitHub Docs
  9. gh pr review - GitHub CLI manual
  10. Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests - GitHub Security Lab