GitHub pull_request_target Workflow on Self-Hosted Runner
Description
Detects when a pull_request_target workflow runs on a self-hosted runner. pull_request_target workflows run with elevated privileges and have access to repository secrets even when triggered by external contributors from forks. When these workflows run on self-hosted runners attackers can gain direct code execution on the underlying infrastructure with potential access to internal network, databases, and systems. Unlike GitHub-hosted runners which are destroyed after each job, self-hosted runners persist and can be permanently compromised. This pattern is high risk regardless of whether the PR is cross-fork or same-repository because self-hosted runners represent infrastructure access. GitHub explicitly warns never to use self-hosted runners with public repositories or workflows that can be triggered by untrusted contributors. This configuration allows any GitHub user with read access to your repository to execute arbitrary code on your infrastructure.
Query
Detection:
- Group:
- ID: PullRequestTarget
RuleID: GitHub.Webhook.PullRequestTargetUsage
- ID: SelfHostedRunner
RuleID: GitHub.Webhook.SelfHostedRunnerUsed
MatchCriteria:
field_name:
- GroupID: PullRequestTarget
Match: workflow_run.id
- GroupID: SelfHostedRunner
Match: workflow_job.run_id
EventEvaluationOrder: Chronological
LookbackWindowMinutes: 1800
Schedule:
RateMinutes: 1440
TimeoutMinutes: 10
Rule dependencies
⚠ Higher-order rule. It fires on other rules' alerts, not on raw events, so it cannot fire on its own. Deploy the rules it depends on too.
Depends on
-
correlates · Panther group
GitHub.Webhook.PullRequestTargetUsagewithin 1800m -
correlates · Panther group
GitHub.Webhook.SelfHostedRunnerUsedwithin 1800m
Analyst notes
-
Stop the self-hosted runner: - SSH/access the runner system - Stop the runner service or unregister the runner
-
Isolate the runner from network: - Block outbound connections via firewall - Disconnect from internal network if possible
-
Review the workflow: - Disable or delete the workflow file that uses pull_request_target + self-hosted - Or modify to use "runs-on: ubuntu-latest"
-
Check runner system for compromise: - Review auth logs for unauthorized access - Check network connections: netstat -tunap | grep ESTABLISHED - Look for persistence mechanisms (cron, systemd, rc.local) - Check for suspicious processes or files - Review bash history for malicious commands
-
Review recent workflow runs: - Check all workflows that ran on this runner in past 7 days - Look for other suspicious activity - Identify if compromise occurred in previous runs
-
Search for indicators of compromise: - Outbound connections to suspicious IPs/domains - New user accounts or SSH keys on runner system - Modified system files or configurations - Cryptocurrency miners or backdoors - Data staging areas or compressed archives