Product News
Security
How to Find GitHub Repos Vulnerable to Supply Chain Attacks Like CanisterWorm
On February 28th, a week-old GitHub account called
hackerbot-claw opened a pull request (#10254, since deleted) on Trivy, a widely-used open-source security scanner, and immediately closed it. The GitHub Actions had already triggered. The attacker had secrets. StepSecurity's analysis confirmed the bot was systematically scanning public repos for exploitable pull_request_target workflows.Aqua Security rotated credentials, but the rotation was incomplete. On March 19th, a separate group (TeamPCP) leveraged surviving credentials to force-push 76 version tags in
trivy-action to point to malicious commits, publish a malicious Trivy binary (v0.69.4), and push compromised Docker Hub images. Every CI pipeline referencing those tags suddenly had its tokens exfiltrated. Those tokens fed into CanisterWorm: a self-propagating npm worm that compromised 135+ malicious package artifacts across 64+ unique packages before npm intervened.The whole chain started with a misconfigured repository setting: fork PRs running GitHub Actions without approval.
What Setting Made This Possible? #
GitHub gives each repo a set of controls for what happens when someone opens a pull request from a fork. For private repos, there's an explicit toggle: allow workflows to run from fork pull requests. For public repos, fork PR workflows are always enabled - the only gate is the approval policy, which controls whether a maintainer has to approve the run before it executes.
When the approval policy is set to
none, any GitHub user can open a fork PR and run arbitrary code in your CI. If your workflows have access to secrets, those secrets leave with the attacker.We've seen teams discover this the hard way. Not because they intentionally misconfigured anything, but because GitHub's defaults changed over time and nobody audited the setting across hundreds of repos. Clicking through every repo's settings page in the UI isn't realistic at scale. We've written about similar audit patterns before - like finding repos with unprotected default branches and PRs merged without review - and this follows the same playbook: turn a manual spot-check into a query you can run across your entire org.
Why We Built github_repository_fork_pr_workflow_settings #
After the CanisterWorm incident, we wanted a way to answer one question across our entire org: which repos are vulnerable to this exact attack? The GitHub API exposes the data through two endpoints, but nobody wants to script that by hand for every repo. So we added a table to CloudQuery's GitHub Source that combines both into a single queryable surface:
That covers the full attack surface: can fork PRs run? Do they get secrets? Do they get write tokens? Does anyone have to approve them first?
How Do You Find Vulnerable Repos at Scale? #
One query covers both public and private repos. Public repos are filtered by approval policy (fork PR workflows are always enabled, so that's the only gate). Private repos are filtered by whether someone explicitly turned on fork PR workflows:
SELECT
r.full_name,
r.visibility,
f.approval_policy,
f.run_workflows_from_fork_pull_requests,
f.send_secrets_and_variables,
f.send_write_tokens_to_workflows
FROM github_repository_fork_pr_workflow_settings f
JOIN github_repositories r ON f.repository_id = r.id
WHERE
(r.visibility = 'public' AND (f.approval_policy = 'none' OR f.approval_policy IS NULL))
OR (r.visibility = 'private' AND f.run_workflows_from_fork_pull_requests = true)
ORDER BY r.visibility, r.full_name;
Repos where
send_secrets_and_variables is also true are the highest risk: fork PRs that run and receive your secrets.How Should You Configure Fork PR Workflow Settings? #
If you're maintaining open-source repos or private repos that accept fork contributions:
- Set the approval policy to
all_outside_collaboratorsat minimum. First-time contributors can't trigger workflows without a maintainer approving the run. For high-value repos, useallto require approval for every fork PR. - Audit
send_secrets_and_variablesandsend_write_tokens_to_workflows. If these are enabled alongside fork PR workflows, attackers who get code execution also get your credentials. - Review workflows using the
pull_request_targettrigger. Even with approval enabled, workflows that check out the fork's HEAD ref (${{ github.event.pull_request.head.ref }}) are running untrusted code in a trusted context. Repo settings alone won't catch this - it requires auditing the workflow files themselves.
If your CI pipelines rely on GitHub Actions from third-party repos, the keyless AWS access with OIDC pattern is worth considering too - it reduces the blast radius of a token exfiltration by scoping credentials to short-lived, narrowly-permissioned sessions.
How Do You Find pull_request_target Workflows with SQL? #
The repo settings tell you if fork PRs can run. But even repos with approval enabled can be vulnerable if their workflow files use
pull_request_target and check out the fork's code. That's what hackerbot-claw exploited on Trivy.CloudQuery's Git Source plugin can sync workflow files from your repos so you can search them with SQL. We covered the plugin's full capabilities in the launch post - it supports syncing any file type with content, from Dockerfiles to CODEOWNERS. Configure it to sync
.github/workflows/* with include_content: true, then join everything together to find repos with loose settings and pull_request_target workflows:SELECT
r.full_name,
f.approval_policy,
gf.path AS workflow_file
FROM github_repository_fork_pr_workflow_settings f
JOIN github_repositories r ON f.repository_id = r.id
JOIN git_files gf ON gf.repository_url LIKE '%' || r.full_name || '%'
WHERE gf.content LIKE '%pull_request_target%'
AND (
(r.visibility = 'public' AND (f.approval_policy = 'none' OR f.approval_policy IS NULL))
OR (r.visibility = 'private' AND f.run_workflows_from_fork_pull_requests = true)
)
ORDER BY r.full_name;
This isn't the only supply chain attack pattern you can detect with CloudQuery. The CodeBreach vulnerability post walks through a similar approach for AWS CodeBuild webhook exploits, and auditing CODEOWNERS against Okta catches orphaned code ownership after employees leave.
How Do You Scope the Blast Radius with CloudQuery Platform? #
The queries above tell you which repos are vulnerable. But if you're responding to an active incident - or you want to report exposure to leadership - you need a way to track and communicate the scope. CloudQuery Platform lets you build reports on top of the synced data, so you can answer questions like: how many repos in our org have fork PRs running without approval? How many of those are also exposing secrets? Which teams own them?
Set up a Policy that flags repos matching the vulnerable criteria from the queries above, and you'll get continuous monitoring with alerts when new repos drift into a risky state. If you're dealing with incident response right now, the report gives you a single view to share with your security team instead of passing around spreadsheets or terminal output.
How to Set This Up #
Add
github_repository_fork_pr_workflow_settings to your synced tables in the CloudQuery GitHub Source. The table syncs to any CloudQuery Destination - PostgreSQL, ClickHouse, BigQuery, whichever your team already uses.We built this table because the CanisterWorm attack exploited a setting that most teams didn't know existed, buried in a UI page that nobody audits at scale. Now you can query it across every repo in your org. If you want to talk through how to set this up or integrate it into your governance workflows, reach out to us.
Audit Your GitHub Repos for Supply Chain Risk
FAQ #
What Is the CanisterWorm Supply Chain Attack? #
CanisterWorm was a self-propagating npm worm discovered in March 2026. It originated from a compromised GitHub Actions workflow on Aqua Security's Trivy project, where stolen credentials were used to tag-poison GitHub Actions and publish malicious packages. The worm spread through compromised npm publisher tokens, affecting 135+ package artifacts across 64+ unique packages before npm intervened.
What Is pull_request_target and Why Is It Dangerous? #
pull_request_target is a GitHub Actions workflow trigger that runs in the context of the base repository rather than the fork. This means it has access to the base repo's secrets and write permissions. If the workflow checks out the fork's code and executes it, an attacker can run arbitrary code with full access to the target repo's credentials.How Do I Check If My GitHub Repos Are Vulnerable to Fork PR Attacks? #
Sync the
github_repository_fork_pr_workflow_settings table using CloudQuery's GitHub Source plugin, then run the SQL query in this post to find repos where fork PRs can run without approval and where secrets are exposed. For a deeper audit, use the Git Source plugin to scan workflow files for pull_request_target usage.What GitHub Actions Approval Policy Should I Use? #
At minimum, set the policy to
all_outside_collaborators so first-time contributors can't trigger workflows without maintainer approval. For repositories with sensitive secrets or write tokens, use all to require approval for every fork PR workflow run.Can CloudQuery Detect pull_request_target in Workflow Files? #
Yes. CloudQuery's Git Source plugin can sync
.github/workflows/* files with their content. You can then query the git_files table with WHERE content LIKE '%pull_request_target%' and join against the GitHub Source tables to correlate workflow triggers with repository fork PR settings.What Destinations Does CloudQuery Support for GitHub Data? #
CloudQuery syncs GitHub data to any supported destination, including PostgreSQL, ClickHouse, BigQuery, Snowflake, S3, and DuckDB. See the full list of available destinations on CloudQuery Hub.
How Often Should I Audit Fork PR Workflow Settings? #
Set up a recurring sync in CloudQuery Platform so the data stays current. Repository settings can change any time a maintainer or admin updates them, and new repos inherit org-level defaults that may not match your security requirements. Running the audit queries on a schedule - or building CloudQuery Policies around them - catches drift before it becomes a vulnerability.
What Other GitHub Security Audits Can I Run with CloudQuery? #
Beyond fork PR settings, you can find repos with unprotected default branches, detect PRs merged without review, audit CODEOWNERS against your identity provider, and track commits by departed employees.