GitHub Cross-Fork Workflow Run


Description

Tracks workflows run in cross-fork pull requests.

Query · python

from panther_base_helpers import deep_get
from panther_github_helpers import is_cross_fork_pr


def rule(event):
    return (
        event.deep_get("workflow_run", "event") in ("pull_request_target", "pull_request")
        and event.get("action") == "requested"
        and is_cross_fork_pr(event) is True
    )


def title(event):
    workflow_name = event.deep_get("workflow_run", "name", default="<UNKNOWN_WORKFLOW>")
    repo_name = deep_get(event, "repository", "full_name", default="<UNKNOWN_REPO>")
    action = event.get("action", "<UNKNOWN_ACTION>")

    title_str = f"Workflow [{workflow_name}] triggered by cross-fork PR in {repo_name} ({action})"
    return title_str
Raw source GitHub Cross-Fork Workflow Run · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
AnalysisType: rule
Filename: github_crossfork_workflow_run.py
RuleID: "GitHub.CrossFork.Workflow.Run"
DisplayName: "GitHub Cross-Fork Workflow Run"
Enabled: true
LogTypes:
  - GitHub.Webhook
Reports:
  MITRE ATT&CK:
    - TA0001:T1195.002  # Supply Chain Compromise: Compromise Software Supply Chain
    - TA0002:T1072  # Execution: Software Deployment Tools
    - TA0004:T1134 # Privilege Escalation: Access Token Manipulation
Tags:
  - CI/CD
  - Workflow
CreateAlert: false
Severity: Info
Description: Tracks workflows run in cross-fork pull requests.
Reference: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows
Tests:
  - Name: "Cross-fork pull request workflow"
    ExpectedResult: true
    Log:
      action: "requested"
      workflow_run:
        id: 87654321
        name: "Build and Test"
        event: "pull_request"
        status: "in_progress"
        conclusion: "failure"
        html_url: "https://github.com/example-org/example-repo/actions/runs/87654321"
        head_branch: "malicious-feature"
        pull_requests:
          - number: 456
            head:
              ref: "malicious-feature"
              repo:
                id: 999999999
                name: "example-repo"
                full_name: "attacker/example-repo"
            base:
              ref: "main"
              repo:
                id: 243627255
                name: "example-repo"
                full_name: "example-org/example-repo"
      repository:
        id: 243627255
        full_name: "example-org/example-repo"
        private: false

  - Name: "Cross-fork push workflow"
    ExpectedResult: false
    Log:
      action: "requested"
      workflow_run:
        id: 87654321
        name: "Build and Test"
        event: "push"
        status: "completed"
        conclusion: "failure"
        html_url: "https://github.com/example-org/example-repo/actions/runs/87654321"
        head_branch: "malicious-feature"
        pull_requests:
          - number: 456
            head:
              ref: "malicious-feature"
              repo:
                id: 999999999
                name: "example-repo"
                full_name: "attacker/example-repo"
            base:
              ref: "main"
              repo:
                id: 243627255
                name: "example-repo"
                full_name: "example-org/example-repo"
      repository:
        id: 243627255
        full_name: "example-org/example-repo"
        private: false

  - Name: "Not cross-fork"
    ExpectedResult: false
    Log:
      action: "requested"
      workflow_run:
        id: 18538851870
        name: "Your-Workflow"
        event: "pull_request_target"
        status: "completed"
        conclusion: "failure"
        html_url: "https://github.com/example-org/example-repo/actions/runs/18538851870"
        head_branch: "deathcon"
        pull_requests: []
        head_repository:
          id: 1072340117
          full_name: "example-org/example-repo"
          fork: false
        repository:
          id: 1072340117
          full_name: "example-org/example-repo"
      repository:
        id: 1072340117
        full_name: "example-org/example-repo"
        private: true

# ------ paired body: github_crossfork_workflow_run.py ------

from panther_base_helpers import deep_get
from panther_github_helpers import is_cross_fork_pr


def rule(event):
    return (
        event.deep_get("workflow_run", "event") in ("pull_request_target", "pull_request")
        and event.get("action") == "requested"
        and is_cross_fork_pr(event) is True
    )


def title(event):
    workflow_name = event.deep_get("workflow_run", "name", default="<UNKNOWN_WORKFLOW>")
    repo_name = deep_get(event, "repository", "full_name", default="<UNKNOWN_REPO>")
    action = event.get("action", "<UNKNOWN_ACTION>")

    title_str = f"Workflow [{workflow_name}] triggered by cross-fork PR in {repo_name} ({action})"
    return title_str

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.