-
Notifications
You must be signed in to change notification settings - Fork 109
ci: auto-approve Dependabot pull requests #733
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| # Automatically approve Dependabot dependency-update pull requests. | ||
| # Runs in the base repository context; it never checks out untrusted PR code. | ||
| name: Auto-approve Dependabot pull requests | ||
|
|
||
| on: | ||
| pull_request_target: | ||
| types: [opened, reopened, synchronize] | ||
| schedule: | ||
| - cron: '17 * * * *' | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: read | ||
| pull-requests: write | ||
|
Comment on lines
+12
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
: "${GH_REPO:?Set GH_REPO=OWNER/REPO}"
workflow=".github/workflows/dependabot-auto-approve.yml"
gh api "repos/${GH_REPO}/actions/permissions/workflow" \
--jq '{default_workflow_permissions, can_approve_pull_request_reviews}'
gh run list \
--repo "$GH_REPO" \
--workflow "$workflow" \
--event pull_request_target \
--limit 20 \
--json databaseId,conclusion,createdAt,displayTitle \
--jq '.[] | select(.conclusion == "failure") | .databaseId' |
while read -r run_id; do
[ -n "$run_id" ] || continue
gh run view "$run_id" --repo "$GH_REPO" --log-failed |
grep -En '403|Resource not accessible|read-only|permission' || true
doneRepository: FailproofAI/failproofai Length of output: 207 🏁 Script executed: #!/usr/bin/env bash
set -u
repo="FailproofAI/failproofai"
workflow=".github/workflows/dependabot-auto-approve.yml"
echo "=== workflow ==="
cat -n "$workflow"
echo "=== recent pull_request_target runs ==="
gh run list \
--repo "$repo" \
--workflow "$workflow" \
--event pull_request_target \
--limit 20 \
--json databaseId,conclusion,createdAt,displayTitle \
--jq '.[]'
echo "=== workflow token settings ==="
gh api "repos/${repo}/actions/permissions/workflow" \
--jq '{default_workflow_permissions, can_approve_pull_request_reviews}'
echo "=== failed-run permission errors ==="
gh run list \
--repo "$repo" \
--workflow "$workflow" \
--event pull_request_target \
--limit 20 \
--json databaseId,conclusion \
--jq '.[] | select(.conclusion == "failure") | .databaseId' |
while read -r run_id; do
[ -n "$run_id" ] || continue
echo "--- run $run_id ---"
gh run view "$run_id" --repo "$repo" --log-failed 2>&1 |
grep -Ein '403|Resource not accessible|read-only|permission' || true
doneRepository: FailproofAI/failproofai Length of output: 2338 🌐 Web query:
💡 Result: When using the pull_request_target event in GitHub Actions, the workflow runs with elevated trust because it uses the base repository's context, rather than the potentially untrusted code from a fork [1]. While this allows the workflow to access repository secrets and obtain a read/write GITHUB_TOKEN, it introduces significant security risks—often called "pwn requests"—if untrusted code from the pull request is checked out and executed [2]. Regarding the use of gh pr review or other gh CLI commands with the GITHUB_TOKEN: 1. Permission Requirements: The GITHUB_TOKEN is restricted by default [3][4]. To use commands that modify pull requests (like requesting reviews or marking them ready), you must explicitly grant the necessary write permissions in your workflow configuration [5][6][7]. For example: permissions: pull-requests: write 2. Unexpected Permission Dependencies: In some cases, even if pull-requests: write is set, certain gh commands may fail with a 403 Forbidden error (Resource not accessible by integration) unless additional permissions, such as contents: write, are also granted [7]. This is often due to the underlying GraphQL or REST API requirements of the specific command [7]. 3. Dependabot and pull_request_target: Workflows triggered by Dependabot are subject to stricter default limitations [8][9]. When a pull request is created by Dependabot, the GITHUB_TOKEN is read-only by default, even in pull_request_target workflows [8]. To perform write operations in such cases, you must manually elevate the token's permissions using the permissions key in your workflow file [9]. 4. Security Best Practices: Always follow the principle of least privilege [5][4]. Only grant the specific scopes required for your workflow to function [5]. Because pull_request_target runs with elevated trust, ensure you are not checking out or executing untrusted code from the pull request unless you have implemented strict security controls (e.g., using secure checkout practices or verifying the PR's origin) [1][2]. Citations:
🌐 Web query:
💡 Result: Using the pull_request_target event with write permissions for the GITHUB_TOKEN presents a significant security risk. Workflows using this event run in the context of the base repository and have access to the repository secrets and the GITHUB_TOKEN, which can be granted write permissions [1]. Because the workflow code is fetched from the base repository but executes in response to a pull request—which may contain untrusted code—an attacker could potentially modify the pull request to execute malicious commands that leverage the write-privileged GITHUB_TOKEN to modify the repository, such as pushing commits or changing release tags. To mitigate these risks: 1. Explicitly set permissions: Always follow the principle of least privilege by explicitly defining the permissions block in your workflow file to ensure the GITHUB_TOKEN only has the minimum necessary access [1]. 2. Avoid write permissions: If possible, configure your workflow to have read-only access by default and only elevate permissions for specific jobs that require them, while carefully auditing the steps within those jobs. 3. Be aware of automation triggers: Note that GitHub enforces specific restrictions on workflows triggered by automation bots like Dependabot, which may force read-only access for the GITHUB_TOKEN even if write permissions are configured [1]. Example of explicit permission configuration: permissions: contents: read jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: # your commands here Citations: 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
url='https://docs.github.com/en/code-security/reference/supply-chain-security/dependabot-on-actions'
curl -L --fail --silent --show-error "$url" |
tr '<' '\n<' |
grep -Eio '.{0,180}(read-only|permissions|pull_request_target|GITHUB_TOKEN|Dependabot).{0,300}' |
head -80Repository: FailproofAI/failproofai Length of output: 12543 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
curl -L --fail --silent --show-error \
'https://docs.github.com/api/article/body?pathname=/en/code-security/reference/supply-chain-security/dependabot-on-actions' |
python3 -c '
import json, sys
text = json.load(sys.stdin) if False else sys.stdin.read()
for i, line in enumerate(text.splitlines(), 1):
if any(term.lower() in line.lower() for term in (
"read-only", "pull_request_target", "GITHUB_TOKEN", "permissions"
)):
print(f"{i}: {line}")
'Repository: FailproofAI/failproofai Length of output: 532 Fix Dependabot event-triggered approvals. For Dependabot-authored pull requests, GitHub makes 🤖 Prompt for AI Agents |
||
|
|
||
| jobs: | ||
| approve: | ||
| name: Approve Dependabot PRs | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Approve open Dependabot pull requests | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| REPOSITORY: ${{ github.repository }} | ||
| run: | | ||
| set -euo pipefail | ||
| gh api --paginate \ | ||
| "/repos/${REPOSITORY}/pulls?state=open&per_page=100" \ | ||
| --jq '.[] | select(.user.login == "dependabot[bot]") | .number' \ | ||
| | while read -r pr; do | ||
| [ -n "$pr" ] || continue | ||
| echo "Approving Dependabot PR #$pr" | ||
| gh pr review "$pr" --repo "$REPOSITORY" --approve \ | ||
| --body "Automatically approved by the organization Dependabot policy." | ||
| done | ||
|
Comment on lines
+27
to
+35
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -u
file=".github/workflows/dependabot-auto-approve.yml"
printf '%s\n' '--- workflow excerpt ---'
cat -n "$file" | sed -n '1,90p'
printf '%s\n' '--- workflow references ---'
rg -n --hidden --glob '!node_modules' 'dependabot-auto-approve|gh pr review|set -e|pipefail|pull_request_target|permissions:' .github README.md 2>/dev/null || true
printf '%s\n' '--- shell behavior probe ---'
bash -euo pipefail -c '
printf "1\n2\n3\n" |
while read -r n; do
printf "attempt %s\n" "$n"
if [ "$n" = 1 ]; then
false
fi
done
printf "after-loop\n"
' >/tmp/original-loop.out 2>/tmp/original-loop.err
status=$?
printf 'status=%s\n' "$status"
cat /tmp/original-loop.out
cat /tmp/original-loop.errRepository: FailproofAI/failproofai Length of output: 1884 Continue processing after each failed review. With 🤖 Prompt for AI Agents |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: FailproofAI/failproofai
Length of output: 8190
🌐 Web query:
GitHub Actions pull_request_target job-level if permissions untrusted pull requests official documentation💡 Result:
The pull_request_target trigger in GitHub Actions is inherently privileged, as it runs using the base repository's context, including access to secrets and read/write repository tokens, even when triggered by a pull request from a fork [1][2][3]. Because of this, executing untrusted code from an external fork within such a workflow can lead to severe security compromises, often referred to as "pwn requests" [4][5][6]. To secure workflows using pull_request_target, official documentation and security best practices recommend the following: 1. Use 'if' Conditionals to Restrict Execution: You can use a job-level 'if' conditional to restrict privileged steps to internal pull requests, preventing them from running on untrusted code from forks [7][8]. jobs: privileged-job: if: github.event.pull_request.head.repo.full_name == github.repository runs-on: ubuntu-latest steps:... 2. Implement Human-in-the-Loop Gates: For public projects, you can combine the trigger with manual approval requirements, such as checking for specific labels added by maintainers after they have reviewed the code [8][9]. jobs: build: if: contains(github.event.pull_request.labels.*.name, 'safe-to-test')... 3. Separate Privileged and Unprivileged Workflows: The most secure pattern is to use the standard pull_request trigger (which is unprivileged for forks) to run tests or build steps, and use a second workflow triggered by workflow_run to handle privileged tasks only after the initial, untrusted checks have passed [2][10][3]. 4. Important Safeguards: - Avoid Checking Out Untrusted Code: Do not check out and execute code from a fork in a workflow that has access to secrets [1][6]. - GitHub Checkout Protection: As of June 2026, GitHub actions/checkout will fail when used in a pull_request_target event from a fork with insecure configurations (e.g., checking out head refs), unless explicitly opted out with allow-unsafe-pr-checkout: true [4]. Only use this flag after verifying that the workflow does not execute the checked-out code [1]. - Apply Least Privilege: Always set explicit permissions at the job or workflow level to restrict what the GITHUB_TOKEN can do [1][10]. By default, pull_request_target workflows run using the version of the workflow file from the base repository's default branch, which prevents attackers from modifying the workflow's behavior via a pull request [1][3]. The vulnerability arises only when that trusted workflow explicitly fetches and executes untrusted code from the pull request head [3].
Citations:
🏁 Script executed:
Repository: FailproofAI/failproofai
Length of output: 710
🏁 Script executed:
Repository: FailproofAI/failproofai
Length of output: 710
Restrict privileged runs to Dependabot pull requests.
The workflow grants
pull-requests: writeand starts a runner for every matching pull request. Add a job-level actor check while allowing scheduled and manual runs:🧰 Tools
🪛 zizmor (1.29.0)
[error] 5-10: use of fundamentally insecure workflow trigger (dangerous-triggers): pull_request_target is almost always used insecurely
(dangerous-triggers)
🤖 Prompt for AI Agents
Source: Linters/SAST tools