Detection rules › Panther

GitHub Cross-Fork Workflow Run

Severity
informational
Log types
GitHub.Webhook
Tags
CI/CD, Workflow
Reference
https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows
Source
github.com/panther-labs/panther-analysis

Tracks workflows run in cross-fork pull requests.

MITRE ATT&CK coverage

Rule body yaml

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

Detection logic

Condition

workflow_run.event in ["pull_request_target", "pull_request"]
action eq "requested"

This rule also runs imperative logic the parser cannot express as a filter; the conditions above are the structured part it could extract.

Indicators

Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.

FieldKindValues
actioneq
  • requested
workflow_run.eventin
  • pull_request
  • pull_request_target