Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions descriptions/edges/GH_CanRequestOIDCTokenFor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# GH_CanRequestOIDCTokenFor

## General Information

The traversable GH_CanRequestOIDCTokenFor edge represents that a GitHub Actions workflow job execution context can request a GitHub-signed OIDC token containing claims for its associated GitHub Environment.

This edge is derived from the existing GH_DeploysTo relationship and the job's calculated `effective_github_token_permissions`. The collector emits it only when the job targets a statically resolved environment and its effective permissions include `id-token:write`.

This is a capability edge, not evidence that the workflow has historically requested a token or contains an explicit OIDC-related step. Code executing in a job with `id-token:write` can request the token directly.

## Edge Schema

| Source | Destination | Traversable |
| --- | --- | --- |
| `GH_WorkflowJob` | `GH_Environment` | `true` |

## Diagram

```mermaid
graph LR
n0["GH_WorkflowJob"]
n1["GH_Environment"]
n0 -->|GH_CanRequestOIDCTokenFor| n1
```
6 changes: 4 additions & 2 deletions descriptions/nodes/GH_AppInstallation.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

## General Information

Represents a GitHub App installed on an organization. App installations have specific permissions and can be scoped to all repositories or a selection of repositories. The permissions granted to the app are captured as a JSON string in the properties.
Represents a GitHub App installed on an organization. App installations have specific permissions and can be scoped to all repositories or a selection of repositories. The permissions granted to the installation are stored as `scope:access` values such as `contents:write` in the `permissions` property.

Unlike fine-grained personal access tokens, GitHub does not expose separate organization and repository permission buckets for app installations, so this property remains a single flat permission list.

Each installation is linked to its parent GH_App via a GH_InstalledAs edge. For installations with `repository_selection` set to `all`, GH_CanAccess edges are created to every repository in the organization. For installations with `repository_selection` set to `selected`, repository-level edges cannot be enumerated with a PAT (requires app installation token authentication).

Expand All @@ -24,7 +26,7 @@ Each installation is linked to its parent GH_App via a GH_InstalledAs edge. For
| `repositories_url` | `string` | API URL to list repositories accessible to this installation. |
| `repository_selection` | `string` | Whether the app has access to `all` repositories or `selected` repositories. |
| `target_type` | `string` | The target type of the installation (e.g., `Organization`). |
| `permissions` | `string` | JSON string of the permissions granted to the app (e.g., `{"contents": "read", "metadata": "read"}`). |
| `permissions` | `list[string]` | Permissions granted to the installation in `scope:access` form. |
| `events` | `string` | JSON string of the webhook events the app subscribes to. |
| `created_at` | `datetime` | When the app was installed. |
| `updated_at` | `datetime` | When the installation was last updated. |
Expand Down
3 changes: 2 additions & 1 deletion descriptions/nodes/GH_Enterprise.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ A GitHub Enterprise account that contains organizations, enterprise teams, roles
| `created_at` | `string` | When the enterprise was created. |
| `updated_at` | `string` | When the enterprise was last updated. |
| `billing_email` | `string` | The enterprise billing email. |
| `security_contact_email` | `string` | The enterprise security contact email. |
| `viewer_is_admin` | `boolean` | Whether the authenticated viewer is an enterprise admin. |
| `github_deployment_type` | `string` | The GitHub deployment type, such as `ghec` or `ghes`. |
| `ghes_version` | `string` | The GitHub Enterprise Server version, when applicable. |
| `environment_name` | `string` | The enterprise environment name. |
| `query_organizations` | `string` | Query for contained organizations. |

Expand Down
3 changes: 0 additions & 3 deletions descriptions/nodes/GH_EnterpriseRunner.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ When the runner is not explicitly marked ephemeral, GH_CanInterceptJob edges ide
graph LR
n0["GH_EnterpriseRunnerGroup"]
n1["GH_EnterpriseRunner"]
n2["GH_WorkflowJob"]
n0 -.->|GH_Contains| n1
n0 -->|GH_HasRunner| n1
n2 -.->|GH_RunsOn| n1
n1 -->|GH_CanInterceptJob| n2
```
3 changes: 3 additions & 0 deletions descriptions/nodes/GH_Environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Represents a GitHub Actions deployment environment configured on a repository. E

Repositories always contain their environments. When custom branch policies are configured, the environment also contains one or more GH_EnvironmentBranchPolicy nodes that describe which branches are allowed to deploy. Environment-scoped secrets and variables are modeled as child nodes of the environment and become available to workflow jobs that reference it.

GH_CanRequestOIDCTokenFor edges from GH_WorkflowJob nodes identify jobs whose execution context can request a GitHub-signed OIDC token for this environment because their effective `GITHUB_TOKEN` permissions include `id-token:write`.

## Properties

| Property | Type | Description |
Expand Down Expand Up @@ -56,5 +58,6 @@ graph LR
n7 -->|GH_CanDeployToEnvironment| n1
n8 -.->|GH_ApprovesDeploymentTo| n1
n8 -->|GH_CanDeployToEnvironment| n1
n9 -->|GH_CanRequestOIDCTokenFor| n1
n9 -.->|GH_DeploysTo| n1
```
1 change: 1 addition & 0 deletions descriptions/nodes/GH_EnvironmentSecret.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ graph LR
n3["GH_WorkflowStep"]
n0 -.->|GH_Contains| n1
n0 -->|GH_HasSecret| n1
n2 -->|GH_CanAccessSecret| n1
n2 -.->|GH_UsesSecret| n1
n3 -.->|GH_UsesSecret| n1
```
3 changes: 0 additions & 3 deletions descriptions/nodes/GH_OrgRunner.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ When the runner is not explicitly marked ephemeral, GH_CanInterceptJob edges ide
graph LR
n0["GH_OrgRunnerGroup"]
n1["GH_OrgRunner"]
n2["GH_WorkflowJob"]
n0 -.->|GH_Contains| n1
n0 -->|GH_HasRunner| n1
n2 -.->|GH_RunsOn| n1
n1 -->|GH_CanInterceptJob| n2
```
1 change: 1 addition & 0 deletions descriptions/nodes/GH_OrgSecret.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ graph LR
n0 -->|GH_CanReadSecret| n1
n2 -.->|GH_Contains| n1
n3 -->|GH_HasSecret| n1
n4 -->|GH_CanAccessSecret| n1
n4 -.->|GH_UsesSecret| n1
n5 -.->|GH_UsesSecret| n1
```
2 changes: 2 additions & 0 deletions descriptions/nodes/GH_Organization.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ Represents a GitHub organization. This is the root node of the graph and serves
| `self_hosted_runners_enabled_repositories` | `string` | Which repositories may use self-hosted runners: `all`, `selected`, or `none`. |
| `default_workflow_permissions` | `string` | The default workflow permissions property. |
| `can_approve_pull_request_reviews` | `boolean` | The can approve pull request reviews property. |
| `github_deployment_type` | `string` | The GitHub deployment type, such as `ghec` or `ghes`. |
| `ghes_version` | `string` | The GitHub Enterprise Server version, when applicable. |
| `query_organization_roles` | `string` | Query for organization roles. |
| `query_users` | `string` | Query for users. |
| `query_teams` | `string` | Query for teams. |
Expand Down
8 changes: 5 additions & 3 deletions descriptions/nodes/GH_PersonalAccessToken.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

## General Information

Represents a fine-grained personal access token that has been granted access to organization resources. PATs are linked to their owning user, the organization, and the repositories they can access. The permissions granted to the token are captured as a JSON string in the properties.
Represents a fine-grained personal access token that has been granted access to organization resources. PATs are linked to their owning user, the organization, and the repositories they can access.

The granted permissions are stored separately as `organization_permissions` and `repository_permissions`. Each property is a list of `scope:access` values such as `members:read` or `contents:write`, matching the permission format used on GH_WorkflowJob nodes.

## Properties

Expand All @@ -19,8 +21,8 @@ Represents a fine-grained personal access token that has been granted access to
| `token_expires_at` | `datetime` | The ISO 8601 timestamp of when the token expires. |
| `token_last_used_at` | `datetime` | The ISO 8601 timestamp of when the token was last used. |
| `access_granted_at` | `datetime` | The ISO 8601 timestamp of when the token was granted to the organization. |. |
| `organization_permissions` | `string` | JSON string of the PAT's organization-scoped permissions. |
| `repository_permissions` | `string` | JSON string of the PAT's repository-scoped permissions. |
| `organization_permissions` | `list[string]` | Organization-scoped permissions in `scope:access` form. |
| `repository_permissions` | `list[string]` | Repository-scoped permissions in `scope:access` form. |
| `token_name` | `string` | The user-assigned display name of the token. |
| `owner_login` | `string` | The login handle of the user who owns the token. |
| `repository_selection` | `string` | Whether the token has access to `all`, `subset`, or `none` of the organization's repositories. |
Expand Down
6 changes: 5 additions & 1 deletion descriptions/nodes/GH_PersonalAccessTokenRequest.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

## General Information

Represents a pending request from an organization member to access organization resources with a fine-grained personal access token. PAT requests are linked to their owning user and the organization. The requested permissions are captured as a JSON string in the properties.
Represents a pending request from an organization member to access organization resources with a fine-grained personal access token. PAT requests are linked to their owning user and the organization.

The requested permissions are stored separately as `organization_permissions` and `repository_permissions`. Each property is a list of `scope:access` values such as `members:read` or `contents:write`, matching the permission format used on GH_WorkflowJob nodes.

## Properties

Expand All @@ -18,6 +20,8 @@ Represents a pending request from an organization member to access organization
| `repository_selection` | `string` | Whether the request targets `all`, `subset`, or `none` of the organization's repositories. |
| `reason` | `string` | The rationale provided by the requester for the access request. |
| `org_name` | `string` | The org name property. |
| `organization_permissions` | `list[string]` | Requested organization-scoped permissions in `scope:access` form. |
| `repository_permissions` | `list[string]` | Requested repository-scoped permissions in `scope:access` form. |
| `query_organization_permissions` | `string` | Query for organization permissions. |
| `query_user` | `string` | Query for user. |
| `query_repositories` | `string` | Query for repositories. |
Expand Down
3 changes: 0 additions & 3 deletions descriptions/nodes/GH_RepoRunner.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ When the runner is not explicitly marked ephemeral, GH_CanInterceptJob edges ide
graph LR
n0["GH_Repository"]
n1["GH_RepoRunner"]
n2["GH_WorkflowJob"]
n0 -.->|GH_CanUseRunner| n1
n0 -.->|GH_Contains| n1
n2 -.->|GH_RunsOn| n1
n1 -->|GH_CanInterceptJob| n2
```
1 change: 1 addition & 0 deletions descriptions/nodes/GH_RepoSecret.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ graph LR
n3["GH_WorkflowStep"]
n0 -.->|GH_Contains| n1
n0 -->|GH_HasSecret| n1
n2 -->|GH_CanAccessSecret| n1
n2 -.->|GH_UsesSecret| n1
n3 -.->|GH_UsesSecret| n1
```
8 changes: 6 additions & 2 deletions descriptions/nodes/GH_Repository.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Represents a GitHub repository within the organization. Repository nodes capture

For repositories with active workflows, the collector records the applicable default workflow permissions and whether workflows may approve pull request reviews. These properties preserve the repository-level policy input later used to derive effective GITHUB_TOKEN permissions for GH_WorkflowJob nodes.

The `branch_count` and `environment_count` properties preserve GitHub-reported totals from the repository GraphQL response. These values can be compared to collected GH_Branch and GH_Environment children to identify incomplete collection before relying on branch- or environment-dependent analysis.

## Properties

| Property | Type | Description |
Expand Down Expand Up @@ -39,11 +41,13 @@ For repositories with active workflows, the collector records the applicable def
| `environment_name` | `string` | The name of the environment (GitHub organization). |
| `actions_enabled` | `boolean` | Whether GitHub Actions is enabled for this repository. |
| `self_hosted_runners_enabled` | `boolean` | Whether the repository may use self-hosted runners. |
| `default_workflow_permissions` | `string` | The repository's applicable default GITHUB_TOKEN workflow permissions. |
| `can_approve_pull_request_reviews` | `boolean` | Whether workflows may approve pull request reviews. |
| `secret_scanning` | `string` | Status of secret scanning (e.g., `enabled`, `disabled`). |
| `branch_ruleset_count` | `integer` | Number of branch-targeted rulesets that apply to this repository. |
| `has_branch_rulesets` | `boolean` | Whether at least one branch-targeted ruleset applies to this repository. |
| `default_workflow_permissions` | `string` | The repository's applicable default GITHUB_TOKEN workflow permissions. |
| `can_approve_pull_request_reviews` | `boolean` | Whether workflows may approve pull request reviews. |
| `branch_count` | `integer` | Number of branch refs reported by GitHub for this repository. |
| `environment_count` | `integer` | Number of deployment environments reported by GitHub for this repository. |
| `query_branches` | `string` | Query for branches. |
| `query_protected_branches` | `string` | Query for protected branches. |
| `query_branch_protection_rules` | `string` | Query for branch protection rules. |
Expand Down
3 changes: 3 additions & 0 deletions descriptions/nodes/GH_Runner.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@ Generic label applied to GitHub self-hosted runner nodes across enterprise, orga
```mermaid
graph LR
n0["GH_Runner"]
n1["GH_WorkflowJob"]
n0 -->|GH_CanInterceptJob| n1
n1 -.->|GH_RunsOn| n0
```
2 changes: 1 addition & 1 deletion descriptions/nodes/GH_Workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ When present, `workflow_permissions` captures the top-level `permissions` declar
| `html_url` | `string` | The GitHub web URL for the workflow file. |
| `branch` | `string` | The branch where the workflow file was found. |
| `contents` | `string` | The content of the workflow file. |
| `workflow_permissions` | `list[string]` | Permissions declared at the workflow level. |
| `triggers` | `list[string]` | The triggers value. |
| `trigger_dispatch_inputs` | `list[string]` | The trigger dispatch inputs value. |
| `is_pwn_requestable` | `boolean` | The is pwn requestable value. |
| `workflow_permissions` | `list[string]` | Permissions declared at the workflow level. |
| `query_repository` | `string` | Query for repository. |
| `query_jobs` | `string` | Query for workflow jobs. |
| `query_execution` | `string` | Query for workflow executions. |
Expand Down
49 changes: 25 additions & 24 deletions descriptions/nodes/GH_WorkflowJob.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ When the job has a statically resolvable self-hosted `runs-on` selector, GH_Runs

When present, `job_permissions` captures the job-level `permissions` declaration from the workflow YAML. `effective_github_token_permissions` captures the calculated static `GITHUB_TOKEN` permissions after applying the repository default, workflow-level declaration, and job-level declaration.

GH_CanAccessSecret edges identify secrets statically referenced by the job's modeled steps or job-level `env` block that the job execution context can access. GH_CanInterceptJob edges from GH_Runner nodes not explicitly marked ephemeral identify jobs whose future execution context may be exposed if that runner is controlled.
GH_CanAccessSecret edges identify secrets statically referenced by the job's modeled steps or job-level `env` block that the job execution context can access. GH_CanInterceptJob edges from GH_Runner nodes not explicitly marked ephemeral identify jobs whose future execution context may be exposed if that runner is controlled. When a job targets an environment and its effective permissions include `id-token:write`, GH_CanRequestOIDCTokenFor identifies the environment OIDC context that code executing in the job can request.

When `runs_on_is_dynamic` is true, runner matching and interception status remain unresolved: the collector does not emit GH_CanInterceptJob edges for the job, so `query_interceptable_jobs` cannot match it and the absence of an edge must not be treated as evidence that the job is definitively non-interceptable.

Expand Down Expand Up @@ -47,31 +47,32 @@ When `runs_on_is_dynamic` is true, runner matching and interception status remai

```mermaid
graph LR
n0["GH_Workflow"]
n0["GH_Runner"]
n1["GH_WorkflowJob"]
n2["GH_Environment"]
n3["GH_EnvironmentSecret"]
n4["GH_EnvironmentVariable"]
n5["GH_OrgSecret"]
n6["GH_OrgVariable"]
n7["GH_RepoSecret"]
n8["GH_RepoVariable"]
n9["GH_Runner"]
n2["GH_Workflow"]
n3["GH_Environment"]
n4["GH_EnvironmentSecret"]
n5["GH_EnvironmentVariable"]
n6["GH_OrgSecret"]
n7["GH_OrgVariable"]
n8["GH_RepoSecret"]
n9["GH_RepoVariable"]
n10["GH_WorkflowStep"]
n0 -.->|GH_Contains| n1
n1 -.->|GH_DeploysTo| n2
n1 -.->|GH_UsesSecret| n3
n1 -.->|GH_UsesVariable| n4
n1 -.->|GH_UsesSecret| n5
n1 -.->|GH_UsesVariable| n6
n1 -.->|GH_UsesSecret| n7
n1 -.->|GH_UsesVariable| n8
n1 -.->|GH_RunsOn| n9
n1 -->|GH_CanAccessSecret| n3
n1 -->|GH_CanAccessSecret| n5
n1 -->|GH_CanAccessSecret| n7
n9 -->|GH_CanInterceptJob| n1
n1 -.->|GH_CallsWorkflow| n0
n0 -->|GH_CanInterceptJob| n1
n2 -.->|GH_Contains| n1
n1 -->|GH_CanRequestOIDCTokenFor| n3
n1 -.->|GH_DeploysTo| n3
n1 -->|GH_CanAccessSecret| n4
n1 -.->|GH_UsesSecret| n4
n1 -.->|GH_UsesVariable| n5
n1 -->|GH_CanAccessSecret| n6
n1 -.->|GH_UsesSecret| n6
n1 -.->|GH_UsesVariable| n7
n1 -->|GH_CanAccessSecret| n8
n1 -.->|GH_UsesSecret| n8
n1 -.->|GH_UsesVariable| n9
n1 -.->|GH_RunsOn| n0
n1 -.->|GH_CallsWorkflow| n2
n1 -.->|GH_DependsOn| n1
n1 -.->|GH_Contains| n10
```
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "GitHub: Tier Zero App Installations (All Repositories)",
"description": "GitHub App installations scoped to all repositories in the organization that have at least one write permission. A compromised app credential grants write access to every repository. Installations with only read permissions are excluded — they pose a data exfiltration risk but do not grant control over the organization.",
"cypher": "MATCH (n:GH_AppInstallation {repository_selection:'all'})\nWHERE n.permissions CONTAINS '\"write\"'\nRETURN n",
"cypher": "MATCH (n:GH_AppInstallation {repository_selection:'all'})\nWHERE ANY(permission IN n.permissions WHERE permission ENDS WITH ':write')\nRETURN n",
"enabled": true,
"zone": "Tier Zero",
"allow_disable": true
Expand Down
2 changes: 1 addition & 1 deletion extension/privilege_zone_rules/t0-apps-all-repos.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "GitHub: Tier Zero Apps (All-Repository Installations)",
"description": "GitHub App definitions whose installations have write access to all repositories. The app owner controls the private key that can generate tokens for any installation. Compromise of the app's private key grants write access to every repository in organizations where it is installed. Apps whose installations have only read permissions are excluded.",
"cypher": "MATCH (n:GH_App)-[:GH_InstalledAs]->(i:GH_AppInstallation {repository_selection:'all'})\nWHERE i.permissions CONTAINS '\"write\"'\nRETURN n",
"cypher": "MATCH (n:GH_App)-[:GH_InstalledAs]->(i:GH_AppInstallation {repository_selection:'all'})\nWHERE ANY(permission IN i.permissions WHERE permission ENDS WITH ':write')\nRETURN n",
"enabled": true,
"zone": "Tier Zero",
"allow_disable": true
Expand Down
2 changes: 1 addition & 1 deletion extension/privilege_zone_rules/t0-pats-all-repos.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "GitHub: Tier Zero PATs (All Repositories)",
"description": "Fine-grained personal access tokens scoped to all repositories in the organization that have at least one write permission. A single compromised token grants write access to every repository. PATs with only read permissions are excluded — they pose a data exfiltration risk but do not grant control over the organization.",
"cypher": "MATCH (n:GH_PersonalAccessToken {repository_selection:'all'})\nWHERE n.permissions CONTAINS '\"write\"'\nRETURN n",
"cypher": "MATCH (n:GH_PersonalAccessToken {repository_selection:'all'})\nWHERE ANY(permission IN n.repository_permissions WHERE permission ENDS WITH ':write')\nRETURN n",
"enabled": true,
"zone": "Tier Zero",
"allow_disable": true
Expand Down
Loading
Loading