diff --git a/.gitignore b/.gitignore index c0e85d6..cac8bd5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Custom *.duckdb ui_catalog.db +docs/official-docs/ site/ addons/ collectors/ @@ -13,6 +14,9 @@ dbt_packages *.pem source +# Codex +.codex + # Byte-compiled / optimized / DLL files __pycache__/ *.py[codz] diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..c297b02 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "docs/og-docs-automation"] + path = docs/og-docs-automation + url = https://github.com/SpecterOps/og-docs-automation diff --git a/descriptions/edges/GH_AddAssignee.md b/descriptions/edges/GH_AddAssignee.md index c519fa1..34c648d 100644 --- a/descriptions/edges/GH_AddAssignee.md +++ b/descriptions/edges/GH_AddAssignee.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_AddAssignee` edge represents a role's ability to assign users to issues and pull requests. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_AddAssignee edge represents a role's ability to assign users to issues and pull requests. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_AddCollaborator.md b/descriptions/edges/GH_AddCollaborator.md index b023bb9..0b5e07f 100644 --- a/descriptions/edges/GH_AddCollaborator.md +++ b/descriptions/edges/GH_AddCollaborator.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_AddCollaborator` edge represents that a role has the ability to add outside collaborators to organization repositories. This permission is typically restricted to Owners, as it grants repository access to external users who are not members of the organization. Outside collaborators bypass organizational membership controls, making this permission significant for security because it can be used to grant access to untrusted external identities without the visibility that full membership provides. +The non-traversable GH_AddCollaborator edge represents that a role has the ability to add outside collaborators to organization repositories. This permission is typically restricted to Owners, as it grants repository access to external users who are not members of the organization. Outside collaborators bypass organizational membership controls, making this permission significant for security because it can be used to grant access to untrusted external identities without the visibility that full membership provides. diff --git a/descriptions/edges/GH_AddLabel.md b/descriptions/edges/GH_AddLabel.md index 922eec0..a295b14 100644 --- a/descriptions/edges/GH_AddLabel.md +++ b/descriptions/edges/GH_AddLabel.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_AddLabel` edge represents a role's ability to add labels to issues and pull requests. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_AddLabel edge represents a role's ability to add labels to issues and pull requests. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_AddMember.md b/descriptions/edges/GH_AddMember.md index 4e865e8..2401de1 100644 --- a/descriptions/edges/GH_AddMember.md +++ b/descriptions/edges/GH_AddMember.md @@ -1,3 +1,3 @@ ## General Information -The traversable `GH_AddMember` edge indicates that a team role with the Maintainer permission level can add new members to the team. It is created by `Git-HoundTeam` when enumerating team membership roles. This edge is traversable because the ability to add members grants indirect access -- a maintainer can add any user to the team, and that user then inherits all of the team's repository permissions, effectively expanding the attack surface. +The traversable GH_AddMember edge indicates that a team role with the Maintainer permission level can add new members to the team. This edge is traversable because the ability to add members grants indirect access -- a maintainer can add any user to the team, and that user then inherits all of the team's repository permissions, effectively expanding the attack surface. diff --git a/descriptions/edges/GH_AdminTo.md b/descriptions/edges/GH_AdminTo.md index a357f91..35e3373 100644 --- a/descriptions/edges/GH_AdminTo.md +++ b/descriptions/edges/GH_AdminTo.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_AdminTo` edge represents a role's full administrative access to the repository. Admin is the highest built-in repository role and grants control over all repository settings, including dangerous operations like deleting the repository or modifying its visibility. Admin access bypasses most protections including branch protection rules, unless `enforce_admins` is explicitly enabled on the branch protection rule. This edge is a key permission in the computed branch access model and is a high-value target in attack path analysis. +The non-traversable GH_AdminTo edge represents a role's full administrative access to the repository. Admin is the highest built-in repository role and grants control over all repository settings, including dangerous operations like deleting the repository or modifying its visibility. Admin access bypasses most protections including branch protection rules, unless `enforce_admins` is explicitly enabled on the branch protection rule. This edge is a key permission in the computed branch access model and is a high-value target in attack path analysis. diff --git a/descriptions/edges/GH_BypassBranchProtection.md b/descriptions/edges/GH_BypassBranchProtection.md index 974bf25..1df3e65 100644 --- a/descriptions/edges/GH_BypassBranchProtection.md +++ b/descriptions/edges/GH_BypassBranchProtection.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_BypassBranchProtection` edge represents a role's ability to bypass branch protection rules on the repository. This permission is available to Admin roles and custom roles that have been granted this specific permission. Bypassing branch protection allows merging pull requests without satisfying required review or status check requirements, effectively circumventing the merge gate. This bypass is suppressed when `enforce_admins` is enabled on the branch protection rule, which forces even admins to comply with the protection policy. +The non-traversable GH_BypassBranchProtection edge represents a role's ability to bypass branch protection rules on the repository. This permission is available to Admin roles and custom roles that have been granted this specific permission. Bypassing branch protection allows merging pull requests without satisfying required review or status check requirements, effectively circumventing the merge gate. This bypass is suppressed when `enforce_admins` is enabled on the branch protection rule, which forces even admins to comply with the protection policy. diff --git a/descriptions/edges/GH_BypassPullRequestAllowances.md b/descriptions/edges/GH_BypassPullRequestAllowances.md index a2e5a4d..44a1635 100644 --- a/descriptions/edges/GH_BypassPullRequestAllowances.md +++ b/descriptions/edges/GH_BypassPullRequestAllowances.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_BypassPullRequestAllowances` edge represents a per-actor allowance that bypasses the pull request review requirement on a branch protection rule. Created by `Git-HoundBranch` when collecting BPR bypass allowances, this edge identifies specific users or teams that can merge code without going through the normal PR review process. This is a significant security concern because these actors can push or merge changes directly, circumventing code review controls that protect branch integrity. Note that this bypass is suppressed when `enforce_admins` is enabled on the branch protection rule, meaning even listed actors must follow the PR review requirement. +The non-traversable GH_BypassPullRequestAllowances edge represents a per-actor allowance that bypasses the pull request review requirement on a branch protection rule. This edge identifies specific users or teams that can merge code without going through the normal PR review process. This is a significant security concern because these actors can push or merge changes directly, circumventing code review controls that protect branch integrity. Note that this bypass is suppressed when `enforce_admins` is enabled on the branch protection rule, meaning even listed actors must follow the PR review requirement. diff --git a/descriptions/edges/GH_CallsWorkflow.md b/descriptions/edges/GH_CallsWorkflow.md new file mode 100644 index 0000000..0861184 --- /dev/null +++ b/descriptions/edges/GH_CallsWorkflow.md @@ -0,0 +1,10 @@ +## General Information + +The traversable GH_CallsWorkflow edge links a workflow job to a reusable workflow it invokes via the `uses:` key at the job level. This edge captures the reusable workflow call graph, enabling analysts to trace inherited permissions and secret access through called workflows. + +### Local vs. remote reusable workflows + +- **Local** (`./. github/workflows/_ci.yml`): the destination is matched by `name` against workflows in the same repository. +- **Remote** (`org/repo/.github/workflows/file.yml@ref`): the destination is matched by the full reference string. If the called workflow has not been collected, the edge destination will not resolve. + +The `reusable_ref` property on the edge always contains the raw `uses:` value from the workflow file. diff --git a/descriptions/edges/GH_CanAccess.md b/descriptions/edges/GH_CanAccess.md index bef81e0..c6c016d 100644 --- a/descriptions/edges/GH_CanAccess.md +++ b/descriptions/edges/GH_CanAccess.md @@ -1,3 +1,3 @@ -# General Information +## General Information -The non-traversable `GH_CanAccess` edge indicates that a personal access token or app installation has been granted access to specific repositories. It is created by `Git-HoundPersonalAccessToken` and `Git-HoundPersonalAccessTokenRequest` for PATs, and by `Git-HoundAppInstallation` for app installations. This edge represents the scope of access granted to a token or app rather than a direct attack path, providing visibility into which repositories are reachable through non-human credentials. It is non-traversable because token and app access does not transitively extend to other principals. +The non-traversable GH_CanAccess edge indicates that a personal access token or app installation has been granted access to specific repositories. This edge represents the scope of access granted to a token or app rather than a direct attack path, providing visibility into which repositories are reachable through non-human credentials. It is non-traversable because token and app access does not transitively extend to other principals. diff --git a/descriptions/edges/GH_CanAssumeIdentity.md b/descriptions/edges/GH_CanAssumeIdentity.md index f6d330f..ea9e12a 100644 --- a/descriptions/edges/GH_CanAssumeIdentity.md +++ b/descriptions/edges/GH_CanAssumeIdentity.md @@ -1,3 +1,3 @@ ## General Information -The traversable `GH_CanAssumeIdentity` edge is a hybrid edge connecting GitHub OIDC token sources to cloud identity targets configured for GitHub Actions federation. Created by the collector when matching GitHub OIDC subject claims to cloud workload identity federation configurations, this edge represents a verified path from GitHub Actions to cloud resource access. It is traversable because an attacker who can execute workflows in the source repository, branch, or environment can obtain an OIDC token that the cloud provider will accept, granting access to the associated cloud identity and its permissions. This edge is critical for identifying cross-cloud lateral movement paths from GitHub into Azure and AWS. +The traversable GH_CanAssumeIdentity edge is a hybrid edge connecting GitHub OIDC token sources to cloud identity targets configured for GitHub Actions federation. This edge represents a verified path from GitHub Actions to cloud resource access. It is traversable because an attacker who can execute workflows in the source repository, branch, or environment can obtain an OIDC token that the cloud provider will accept, granting access to the associated cloud identity and its permissions. This edge is critical for identifying cross-cloud lateral movement paths from GitHub into Azure and AWS. diff --git a/descriptions/edges/GH_CanCreateBranch.md b/descriptions/edges/GH_CanCreateBranch.md index 02729b1..1a412e2 100644 --- a/descriptions/edges/GH_CanCreateBranch.md +++ b/descriptions/edges/GH_CanCreateBranch.md @@ -1,6 +1,6 @@ ## General Information -The traversable `GH_CanCreateBranch` edge is a computed edge indicating that a role or actor can create new branches in a repository. Created by `Compute-GitHoundBranchAccess` with no additional API calls, the computation evaluates whether a wildcard (`*`) BPR with push restrictions and `blocks_creations` exists. If no such BPR exists, any write-capable role can create branches. If one exists, admin or `push_protected_branch` permission is required, or the actor must be listed in pushAllowances. Per-actor edges from `GH_User` or `GH_Team` are only emitted when BPR allowances grant branch creation access beyond what the role provides. Each edge includes a `reason` property and a `query_composition` Cypher query showing the underlying graph evidence. +The traversable GH_CanCreateBranch edge is a computed edge indicating that a role or actor can create new branches in a repository. The computation evaluates whether a wildcard (`*`) BPR with push restrictions and `blocks_creations` exists. If no such BPR exists, any write-capable role can create branches. If one exists, admin or `push_protected_branch` permission is required, or the actor must be listed in pushAllowances. Per-actor edges from GH_User or GH_Team are only emitted when BPR allowances grant branch creation access beyond what the role provides. Each edge includes a `reason` property and a `query_composition` Cypher query showing the underlying graph evidence. ## Scenarios @@ -28,7 +28,7 @@ graph LR ### `push_protected_branch` — Push-protected role bypasses wildcard BPR -A wildcard BPR blocks creations. The `GH_PushProtectedBranch` permission bypasses the push gate regardless of `enforce_admins`. +A wildcard BPR blocks creations. The GH_PushProtectedBranch permission bypasses the push gate regardless of `enforce_admins`. ```mermaid graph LR @@ -41,7 +41,7 @@ graph LR ### `push_allowance` — Per-actor push restriction bypass -User or Team listed in the wildcard BPR's `pushAllowances` can create branches. This is a per-actor delta edge — only emitted when the actor's role doesn't already grant `GH_CanCreateBranch`. +User or Team listed in the wildcard BPR's `pushAllowances` can create branches. This is a per-actor delta edge — only emitted when the actor's role doesn't already grant GH_CanCreateBranch. ```mermaid graph LR diff --git a/descriptions/edges/GH_CanEditProtection.md b/descriptions/edges/GH_CanEditProtection.md index ac5be73..455e7eb 100644 --- a/descriptions/edges/GH_CanEditProtection.md +++ b/descriptions/edges/GH_CanEditProtection.md @@ -1,12 +1,12 @@ ## General Information -The traversable `GH_CanEditProtection` edge is a computed edge indicating that a role can modify or remove the branch protection rules governing a specific branch. Created by `Compute-GitHoundBranchAccess` with no additional API calls, this edge is emitted when the role has `GH_EditRepoProtections` or `GH_AdminTo` permissions and the branch is covered by at least one branch protection rule. The edge targets the protected branch (not the BPR itself) because the security impact is evaluated per-branch — a role that can weaken or remove protections on a branch can subsequently push code to it, representing a privilege escalation path. +The traversable GH_CanEditProtection edge is a computed edge indicating that a role can modify or remove the branch protection rules governing a specific branch. This edge is emitted when the role has GH_EditRepoProtections or GH_AdminTo permissions and the branch is covered by at least one branch protection rule. The edge targets the protected branch (not the BPR itself) because the security impact is evaluated per-branch — a role that can weaken or remove protections on a branch can subsequently push code to it, representing a privilege escalation path. ## Scenarios ### `admin` — Admin can edit protections -The admin role has `GH_AdminTo` which implicitly grants the ability to modify or remove any branch protection rule. +The admin role has GH_AdminTo which implicitly grants the ability to modify or remove any branch protection rule. ```mermaid graph LR @@ -18,7 +18,7 @@ graph LR ### `edit_repo_protections` — Explicit edit permission -A custom or standard role with the `GH_EditRepoProtections` permission can modify or remove branch protection rules. +A custom or standard role with the GH_EditRepoProtections permission can modify or remove branch protection rules. ```mermaid graph LR diff --git a/descriptions/edges/GH_CanPwnRequest.md b/descriptions/edges/GH_CanPwnRequest.md new file mode 100644 index 0000000..3c0e4d6 --- /dev/null +++ b/descriptions/edges/GH_CanPwnRequest.md @@ -0,0 +1,59 @@ +## General Information + +The traversable GH_CanPwnRequest edge indicates that a repository role can exploit a pwn-requestable workflow to execute arbitrary code with the base branch's secrets, GITHUB_TOKEN permissions, and OIDC identity. This is a computed edge that combines workflow analysis with repository access and fork policy evaluation. + +### Pwn Request Conditions + +A workflow is considered pwn-requestable (`is_pwn_requestable = true`) when **all** of the following are true: + +1. **`pull_request_target` trigger**: The workflow is triggered by `pull_request_target`, which runs in the context of the base branch (not the fork) and has access to the base branch's secrets and permissions. +2. **Attacker-controlled checkout**: A step uses `actions/checkout` with a `ref` parameter pointing to the pull request head, meaning attacker-supplied code from the fork replaces the trusted repository contents. Detected ref patterns: + - `${{ github.event.pull_request.head.sha }}` + - `${{ github.event.pull_request.head.ref }}` + - `${{ github.head_ref }}` + +### Edge Drawing Conditions + +An edge is drawn from a GH_RepoRole to the repository (and its branches) when: + +1. **Read access**: The role has a GH_ReadRepoContents edge to the repository (read access is the minimum required to fork). +2. **Forkability**: The repository can be forked by the role holder: + - **Public repos**: Always forkable by anyone on GitHub. + - **Private/internal repos**: Requires both the organization setting `members_can_fork_private_repositories = true` AND the repository setting `allow_forking = true`. +3. **Pwn-requestable workflow**: The repository has at least one workflow with `is_pwn_requestable = true`. + +### Branch Targeting + +- If the `pull_request_target` trigger has a `branches:` filter (e.g., `branches: [main]`), edges are drawn only to matching branches and the repository. +- If unconstrained, edges are drawn to the repository and all of its branches. + +### Attack Impact + +An attacker who exploits a pwn request gains code execution in the workflow runner with access to: + +- **Repository secrets** scoped to the base branch +- **Organization secrets** accessible by the repository +- **GITHUB_TOKEN** with the workflow's declared permissions (often `write`) +- **OIDC tokens** if `id-token: write` is set, enabling cloud identity assumption via GH_CanAssumeIdentity +- **Environment secrets** if the workflow job targets a deployment environment + +### Caveats + +- **OIDC traversal requires `id-token: write`**: The attack chain from GH_CanPwnRequest through GH_CanAssumeIdentity to a cloud role is only valid if the pwn-requestable workflow (or job) explicitly declares `id-token: write` in its `permissions:` block. The `id-token` permission defaults to `none` and is never implicitly granted — even when the workflow has no `permissions:` block at all. The `permissions` property on the GH_WorkflowJob node can be inspected to verify this. +- **GITHUB_TOKEN permissions**: The `permissions:` block controls what the `GITHUB_TOKEN` can do (e.g., push commits, create releases), but has no effect on secret access, OIDC token requests (governed separately by `id-token`), or arbitrary code execution. A workflow with `contents: read` is still fully exploitable via pwn request for secret exfiltration and lateral movement — only write-back to the repository is limited. + +```mermaid +graph LR + role("GH_RepoRole repo-read") + repo("GH_Repository private-app") + branch("GH_Branch main") + wf("GH_Workflow vulnerable-ci.yml") + secret("GH_RepoSecret DEPLOY_KEY") + cloud("AWSRole deploy-prod") + + role -- GH_CanPwnRequest --> repo + role -- GH_CanPwnRequest --> branch + repo -.- |GH_HasWorkflow| wf + repo -.- |GH_Contains| secret + branch -- GH_CanAssumeIdentity --> cloud +``` \ No newline at end of file diff --git a/descriptions/edges/GH_CanReadSecretScanningAlert.md b/descriptions/edges/GH_CanReadSecretScanningAlert.md index 66d931a..6c5f5fa 100644 --- a/descriptions/edges/GH_CanReadSecretScanningAlert.md +++ b/descriptions/edges/GH_CanReadSecretScanningAlert.md @@ -1,6 +1,6 @@ ## General Information -The traversable `GH_CanReadSecretScanningAlert` edge is a computed edge indicating that a role can read a specific secret scanning alert, including the leaked secret value. Created by `Compute-GitHoundSecretScanningAccess` with no additional API calls, the computation cross-references `GH_ViewSecretScanningAlerts` permission edges with `GH_Contains` structural edges (org-level and repo-level) to determine which alerts each role can access. This edge is traversable because reading an alert reveals the leaked secret — if the secret is a valid GitHub Personal Access Token, the `GH_ValidToken` edge enables identity compromise of the token's owner. +The traversable GH_CanReadSecretScanningAlert edge is a computed edge indicating that a role can read a specific secret scanning alert, including the leaked secret value. The computation cross-references GH_ViewSecretScanningAlerts permission edges with GH_Contains structural edges (org-level and repo-level) to determine which alerts each role can access. This edge is traversable because reading an alert reveals the leaked secret — if the secret is a valid GitHub Personal Access Token, the GH_ValidToken edge enables identity compromise of the token's owner. Each edge includes a `reason` property (`org_role_permission` or `repo_role_permission`) and a `query_composition` Cypher query showing the underlying graph evidence. @@ -8,7 +8,7 @@ Each edge includes a `reason` property (`org_role_permission` or `repo_role_perm ### `org_role_permission` — Org role views alerts via organization -An org role with `GH_ViewSecretScanningAlerts` to the organization can read all secret scanning alerts across the entire org. The computation follows `GH_Contains` edges from the organization to each alert. +An org role with GH_ViewSecretScanningAlerts to the organization can read all secret scanning alerts across the entire org. The computation follows GH_Contains edges from the organization to each alert. ```mermaid graph LR @@ -20,7 +20,7 @@ graph LR ### `repo_role_permission` — Repo role views alerts via repository -A repo role with `GH_ViewSecretScanningAlerts` to the repository can read secret scanning alerts in that specific repo. The computation follows `GH_Contains` edges from the repository to each alert. +A repo role with GH_ViewSecretScanningAlerts to the repository can read secret scanning alerts in that specific repo. The computation follows GH_Contains edges from the repository to each alert. ```mermaid graph LR diff --git a/descriptions/edges/GH_CanWriteBranch.md b/descriptions/edges/GH_CanWriteBranch.md index b45bbc0..12b6b57 100644 --- a/descriptions/edges/GH_CanWriteBranch.md +++ b/descriptions/edges/GH_CanWriteBranch.md @@ -1,6 +1,6 @@ -# General Information +## General Information -The traversable `GH_CanWriteBranch` edge is a computed edge indicating that a role or actor can push to a specific branch. Created by `Compute-GitHoundBranchAccess` with no additional API calls, the computation evaluates both the merge gate (PR review requirements) and push gate (push restrictions) of any branch protection rule protecting the branch. Role-level edges are the common case; per-actor edges from `GH_User` or `GH_Team` are only emitted when BPR allowances grant access beyond what the role provides. Each edge includes a `reason` property (`no_protection`, `admin`, `push_protected_branch`, `bypass_branch_protection`, `push_allowance`, `bypass_pr_allowance`) and a `query_composition` Cypher query showing the underlying graph evidence. +The traversable GH_CanWriteBranch edge is a computed edge indicating that a role or actor can push to a specific branch. The computation evaluates both the merge gate (PR review requirements) and push gate (push restrictions) of any branch protection rule protecting the branch. Role-level edges are the common case; per-actor edges from GH_User or GH_Team are only emitted when BPR allowances grant access beyond what the role provides. Each edge includes a `reason` property (`no_protection`, `admin`, `push_protected_branch`, `bypass_branch_protection`, `push_allowance`, `bypass_pr_allowance`) and a `query_composition` Cypher query showing the underlying graph evidence. ## Scenarios @@ -29,7 +29,7 @@ graph LR ### `push_protected_branch` — Push gate bypass -Push gate blocked by `push_restrictions` (no merge gate block). The `GH_PushProtectedBranch` permission bypasses the push gate regardless of `enforce_admins`. +Push gate blocked by `push_restrictions` (no merge gate block). The GH_PushProtectedBranch permission bypasses the push gate regardless of `enforce_admins`. ```mermaid graph LR @@ -42,7 +42,7 @@ graph LR ### `bypass_branch_protection` — Merge gate bypass -Merge gate blocked by PR reviews. The `GH_BypassBranchProtection` permission bypasses the merge gate. Requires `enforce_admins=false`; suppressed when `enforce_admins=true`. +Merge gate blocked by PR reviews. The GH_BypassBranchProtection permission bypasses the merge gate. Requires `enforce_admins=false`; suppressed when `enforce_admins=true`. ```mermaid graph LR diff --git a/descriptions/edges/GH_CloseDiscussion.md b/descriptions/edges/GH_CloseDiscussion.md index 2ca6011..b87271b 100644 --- a/descriptions/edges/GH_CloseDiscussion.md +++ b/descriptions/edges/GH_CloseDiscussion.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_CloseDiscussion` edge represents a role's ability to close discussions, preventing further replies. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_CloseDiscussion edge represents a role's ability to close discussions, preventing further replies. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_CloseIssue.md b/descriptions/edges/GH_CloseIssue.md index 9e1b638..d360a6e 100644 --- a/descriptions/edges/GH_CloseIssue.md +++ b/descriptions/edges/GH_CloseIssue.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_CloseIssue` edge represents a role's ability to close issues. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_CloseIssue edge represents a role's ability to close issues. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_ClosePullRequest.md b/descriptions/edges/GH_ClosePullRequest.md index abe27ce..4ed4971 100644 --- a/descriptions/edges/GH_ClosePullRequest.md +++ b/descriptions/edges/GH_ClosePullRequest.md @@ -1,3 +1,3 @@ -# General Information +## General Information -The non-traversable `GH_ClosePullRequest` edge represents a role's ability to close pull requests. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_ClosePullRequest edge represents a role's ability to close pull requests. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_Contains.md b/descriptions/edges/GH_Contains.md index c445055..01de8b8 100644 --- a/descriptions/edges/GH_Contains.md +++ b/descriptions/edges/GH_Contains.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_Contains` edge represents structural containment within the GitHub resource hierarchy. The organization serves as the top-level container for users, teams, repositories, roles, secrets, app installations, and personal access tokens. Repositories contain their own repo-level secrets, and environments contain environment-scoped secrets. This edge is created by the collector to establish the organizational hierarchy of GitHub resources and is not traversable because containment alone does not imply privilege escalation. +The non-traversable GH_Contains edge represents structural containment within the GitHub resource hierarchy. The organization serves as the top-level container for users, teams, repositories, roles, secrets, app installations, and personal access tokens. Repositories contain their own repo-level secrets, and environments contain environment-scoped secrets. This edge is created by the collector to establish the organizational hierarchy of GitHub resources and is not traversable because containment alone does not imply privilege escalation. diff --git a/descriptions/edges/GH_ConvertIssuesToDiscussions.md b/descriptions/edges/GH_ConvertIssuesToDiscussions.md index 3f77b34..4cbd4a2 100644 --- a/descriptions/edges/GH_ConvertIssuesToDiscussions.md +++ b/descriptions/edges/GH_ConvertIssuesToDiscussions.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ConvertIssuesToDiscussions` edge represents a role's ability to convert issues to discussions, moving them from the issue tracker to the discussions forum. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_ConvertIssuesToDiscussions edge represents a role's ability to convert issues to discussions, moving them from the issue tracker to the discussions forum. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_CreateDiscussionCategory.md b/descriptions/edges/GH_CreateDiscussionCategory.md index 72d7b6b..383d0a0 100644 --- a/descriptions/edges/GH_CreateDiscussionCategory.md +++ b/descriptions/edges/GH_CreateDiscussionCategory.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_CreateDiscussionCategory` edge represents a role's ability to create new discussion categories. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_CreateDiscussionCategory edge represents a role's ability to create new discussion categories. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_CreateRepository.md b/descriptions/edges/GH_CreateRepository.md index 09603f1..0481e4e 100644 --- a/descriptions/edges/GH_CreateRepository.md +++ b/descriptions/edges/GH_CreateRepository.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_CreateRepository` edge represents that a role has the ability to create new repositories within the organization. This permission is available to Owners and custom organization roles that have been granted the repository creation permission. Creating repositories can introduce new attack surface to an organization, as each new repository is a potential vector for code execution through GitHub Actions workflows, secret exposure, and supply chain attacks. +The non-traversable GH_CreateRepository edge represents that a role has the ability to create new repositories within the organization. This permission is available to Owners and custom organization roles that have been granted the repository creation permission. Creating repositories can introduce new attack surface to an organization, as each new repository is a potential vector for code execution through GitHub Actions workflows, secret exposure, and supply chain attacks. diff --git a/descriptions/edges/GH_CreateSoloMergeQueueEntry.md b/descriptions/edges/GH_CreateSoloMergeQueueEntry.md index ecfedd7..07dc0b9 100644 --- a/descriptions/edges/GH_CreateSoloMergeQueueEntry.md +++ b/descriptions/edges/GH_CreateSoloMergeQueueEntry.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_CreateSoloMergeQueueEntry` edge represents a role's ability to create solo merge queue entries, effectively bypassing the merge queue by merging independently of other queued changes. This permission is available to Admin roles and custom roles that have been granted this specific permission. Solo merge queue entries skip the batching and ordering guarantees of the merge queue, allowing changes to land without waiting for or being tested alongside other pending merges. This can circumvent the integration testing benefits that merge queues provide. +The non-traversable GH_CreateSoloMergeQueueEntry edge represents a role's ability to create solo merge queue entries, effectively bypassing the merge queue by merging independently of other queued changes. This permission is available to Admin roles and custom roles that have been granted this specific permission. Solo merge queue entries skip the batching and ordering guarantees of the merge queue, allowing changes to land without waiting for or being tested alongside other pending merges. This can circumvent the integration testing benefits that merge queues provide. diff --git a/descriptions/edges/GH_CreateTag.md b/descriptions/edges/GH_CreateTag.md index f1bdb02..14f3e65 100644 --- a/descriptions/edges/GH_CreateTag.md +++ b/descriptions/edges/GH_CreateTag.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_CreateTag` edge represents a role's ability to create tags and releases. This permission is available to Maintain and Admin roles and custom roles that have been granted this specific permission. Creating tags can trigger CI/CD workflows and publish release artifacts. +The non-traversable GH_CreateTag edge represents a role's ability to create tags and releases. This permission is available to Maintain and Admin roles and custom roles that have been granted this specific permission. Creating tags can trigger CI/CD workflows and publish release artifacts. diff --git a/descriptions/edges/GH_CreateTeam.md b/descriptions/edges/GH_CreateTeam.md index 45b6bc3..f310b8f 100644 --- a/descriptions/edges/GH_CreateTeam.md +++ b/descriptions/edges/GH_CreateTeam.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_CreateTeam` edge represents that a role has the ability to create teams within the organization. Teams are the primary mechanism for granting groups of users access to repositories, so team creation is a stepping stone to broader access. This edge is created by the collector when enumerating organization role permissions, and its security significance lies in the fact that a newly created team can be granted repository access and then populated with controlled accounts. +The non-traversable GH_CreateTeam edge represents that a role has the ability to create teams within the organization. Teams are the primary mechanism for granting groups of users access to repositories, so team creation is a stepping stone to broader access. This edge is created by the collector when enumerating organization role permissions, and its security significance lies in the fact that a newly created team can be granted repository access and then populated with controlled accounts. diff --git a/descriptions/edges/GH_DeleteAlertsCodeScanning.md b/descriptions/edges/GH_DeleteAlertsCodeScanning.md index 5c68ed6..3a917e8 100644 --- a/descriptions/edges/GH_DeleteAlertsCodeScanning.md +++ b/descriptions/edges/GH_DeleteAlertsCodeScanning.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_DeleteAlertsCodeScanning` edge represents a role's ability to delete code scanning alerts from the repository. This permission is available to Admin roles and custom roles that have been granted this specific permission. Deleting code scanning alerts can obscure security vulnerabilities that have been detected in the codebase, which is significant from an audit and compliance perspective. An attacker with this permission could suppress evidence of vulnerabilities they have introduced. +The non-traversable GH_DeleteAlertsCodeScanning edge represents a role's ability to delete code scanning alerts from the repository. This permission is available to Admin roles and custom roles that have been granted this specific permission. Deleting code scanning alerts can obscure security vulnerabilities that have been detected in the codebase, which is significant from an audit and compliance perspective. An attacker with this permission could suppress evidence of vulnerabilities they have introduced. diff --git a/descriptions/edges/GH_DeleteDiscussion.md b/descriptions/edges/GH_DeleteDiscussion.md index 071ebd1..0033b84 100644 --- a/descriptions/edges/GH_DeleteDiscussion.md +++ b/descriptions/edges/GH_DeleteDiscussion.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_DeleteDiscussion` edge represents a role's ability to delete discussions. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_DeleteDiscussion edge represents a role's ability to delete discussions. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_DeleteDiscussionComment.md b/descriptions/edges/GH_DeleteDiscussionComment.md index d251db4..bda23c6 100644 --- a/descriptions/edges/GH_DeleteDiscussionComment.md +++ b/descriptions/edges/GH_DeleteDiscussionComment.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_DeleteDiscussionComment` edge represents a role's ability to delete discussion comments authored by any user. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_DeleteDiscussionComment edge represents a role's ability to delete discussion comments authored by any user. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_DeleteIssue.md b/descriptions/edges/GH_DeleteIssue.md index 7e586d3..04ad299 100644 --- a/descriptions/edges/GH_DeleteIssue.md +++ b/descriptions/edges/GH_DeleteIssue.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_DeleteIssue` edge represents a role's ability to delete issues permanently. Deleted issues cannot be recovered. This permission is available to Admin roles and custom roles that have been granted this specific permission. Deleting issues can destroy audit trails and remove evidence of security discussions or vulnerability reports. +The non-traversable GH_DeleteIssue edge represents a role's ability to delete issues permanently. Deleted issues cannot be recovered. This permission is available to Admin roles and custom roles that have been granted this specific permission. Deleting issues can destroy audit trails and remove evidence of security discussions or vulnerability reports. diff --git a/descriptions/edges/GH_DeleteTag.md b/descriptions/edges/GH_DeleteTag.md index a4080ca..755e162 100644 --- a/descriptions/edges/GH_DeleteTag.md +++ b/descriptions/edges/GH_DeleteTag.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_DeleteTag` edge represents a role's ability to delete tags and releases. This permission is available to Admin roles and custom roles that have been granted this specific permission. Deleting tags can break downstream dependency references and remove published artifacts. +The non-traversable GH_DeleteTag edge represents a role's ability to delete tags and releases. This permission is available to Admin roles and custom roles that have been granted this specific permission. Deleting tags can break downstream dependency references and remove published artifacts. diff --git a/descriptions/edges/GH_DependsOn.md b/descriptions/edges/GH_DependsOn.md new file mode 100644 index 0000000..38455b5 --- /dev/null +++ b/descriptions/edges/GH_DependsOn.md @@ -0,0 +1,3 @@ +## General Information + +The non-traversable GH_DependsOn edge represents a `needs:` dependency between two jobs in the same workflow. This edge captures execution order constraints — the source job will not start until the destination job completes successfully. This edge is non-traversable because it represents sequencing only, not an access or privilege path. diff --git a/descriptions/edges/GH_DeploysTo.md b/descriptions/edges/GH_DeploysTo.md new file mode 100644 index 0000000..4689fbe --- /dev/null +++ b/descriptions/edges/GH_DeploysTo.md @@ -0,0 +1,3 @@ +## General Information + +The non-traversable GH_DeploysTo edge links a workflow job to the GitHub Environment it targets via the `environment:` key. This edge records which jobs deploy to which environments. Environments can gate deployments with protection rules (required reviewers, wait timers, deployment branch policies) and can expose environment-scoped secrets. diff --git a/descriptions/edges/GH_EditCategoryOnDiscussion.md b/descriptions/edges/GH_EditCategoryOnDiscussion.md index 447e91d..066529b 100644 --- a/descriptions/edges/GH_EditCategoryOnDiscussion.md +++ b/descriptions/edges/GH_EditCategoryOnDiscussion.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_EditCategoryOnDiscussion` edge represents a role's ability to change the category of a discussion, moving it between categories. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_EditCategoryOnDiscussion edge represents a role's ability to change the category of a discussion, moving it between categories. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_EditDiscussionCategory.md b/descriptions/edges/GH_EditDiscussionCategory.md index d961d79..592d27c 100644 --- a/descriptions/edges/GH_EditDiscussionCategory.md +++ b/descriptions/edges/GH_EditDiscussionCategory.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_EditDiscussionCategory` edge represents a role's ability to edit discussion categories to reorganize discussion classification. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_EditDiscussionCategory edge represents a role's ability to edit discussion categories to reorganize discussion classification. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_EditDiscussionComment.md b/descriptions/edges/GH_EditDiscussionComment.md index 5013e6d..2978aef 100644 --- a/descriptions/edges/GH_EditDiscussionComment.md +++ b/descriptions/edges/GH_EditDiscussionComment.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_EditDiscussionComment` edge represents a role's ability to edit discussion comments authored by any user. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_EditDiscussionComment edge represents a role's ability to edit discussion comments authored by any user. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_EditRepoAnnouncementBanners.md b/descriptions/edges/GH_EditRepoAnnouncementBanners.md index daf2830..75f1a61 100644 --- a/descriptions/edges/GH_EditRepoAnnouncementBanners.md +++ b/descriptions/edges/GH_EditRepoAnnouncementBanners.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_EditRepoAnnouncementBanners` edge represents a role's ability to edit repository announcement banners displayed to visitors. This permission is available to Maintain and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_EditRepoAnnouncementBanners edge represents a role's ability to edit repository announcement banners displayed to visitors. This permission is available to Maintain and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_EditRepoCustomPropertiesValues.md b/descriptions/edges/GH_EditRepoCustomPropertiesValues.md index 0f43ead..f00b434 100644 --- a/descriptions/edges/GH_EditRepoCustomPropertiesValues.md +++ b/descriptions/edges/GH_EditRepoCustomPropertiesValues.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_EditRepoCustomPropertiesValues` edge represents a role's ability to edit custom property values on the repository. This permission is available to Admin roles and custom roles that have been granted this specific permission. Custom properties are organization-defined metadata fields on repositories that can be used for classification, compliance tagging, or policy enforcement via rulesets. Modifying custom property values could alter which organization-level rulesets apply to the repository, potentially bypassing security controls that are scoped by property-based targeting. +The non-traversable GH_EditRepoCustomPropertiesValues edge represents a role's ability to edit custom property values on the repository. This permission is available to Admin roles and custom roles that have been granted this specific permission. Custom properties are organization-defined metadata fields on repositories that can be used for classification, compliance tagging, or policy enforcement via rulesets. Modifying custom property values could alter which organization-level rulesets apply to the repository, potentially bypassing security controls that are scoped by property-based targeting. diff --git a/descriptions/edges/GH_EditRepoMetadata.md b/descriptions/edges/GH_EditRepoMetadata.md index 7d73576..4c650c9 100644 --- a/descriptions/edges/GH_EditRepoMetadata.md +++ b/descriptions/edges/GH_EditRepoMetadata.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_EditRepoMetadata` edge represents a role's ability to edit repository metadata including description, homepage URL, and visibility settings. This permission is available to Maintain and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_EditRepoMetadata edge represents a role's ability to edit repository metadata including description, homepage URL, and visibility settings. This permission is available to Maintain and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_EditRepoProtections.md b/descriptions/edges/GH_EditRepoProtections.md index 49e5da2..de39956 100644 --- a/descriptions/edges/GH_EditRepoProtections.md +++ b/descriptions/edges/GH_EditRepoProtections.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_EditRepoProtections` edge represents a role's ability to edit or remove branch protection rules on the repository. This permission is available to Admin roles and custom roles that have been granted this specific permission. Modifying a branch protection rule is an indirect bypass -- removing or weakening protections opens the branch to direct push or unreviewed merges, making this a high-severity permission from a security perspective. Attack paths that include this edge can escalate to full branch write access by first disabling protections. +The non-traversable GH_EditRepoProtections edge represents a role's ability to edit or remove branch protection rules on the repository. This permission is available to Admin roles and custom roles that have been granted this specific permission. Modifying a branch protection rule is an indirect bypass -- removing or weakening protections opens the branch to direct push or unreviewed merges, making this a high-severity permission from a security perspective. Attack paths that include this edge can escalate to full branch write access by first disabling protections. diff --git a/descriptions/edges/GH_HasBaseRole.md b/descriptions/edges/GH_HasBaseRole.md index cf5d40a..2a79127 100644 --- a/descriptions/edges/GH_HasBaseRole.md +++ b/descriptions/edges/GH_HasBaseRole.md @@ -1,3 +1,3 @@ ## General Information -The traversable `GH_HasBaseRole` edge represents role inheritance within the GitHub permission hierarchy. Org roles inherit down to all-repo roles (e.g., Owners inherits to all_repo_admin), and custom roles inherit from their base roles (e.g., a custom_role inherits from write). It is created by `Git-HoundOrganization` (for org-to-repo role inheritance) and `Git-HoundRepository` (for repo-level role inheritance). This edge is traversable because it extends permissions through the role hierarchy, meaning a principal with a higher-level role implicitly holds all inherited lower-level roles. +The traversable GH_HasBaseRole edge represents role inheritance within the GitHub permission hierarchy. Org roles inherit down to all-repo roles (e.g., Owners inherits to all_repo_admin), and custom roles inherit from their base roles (e.g., a custom_role inherits from write). This edge is traversable because it extends permissions through the role hierarchy, meaning a principal with a higher-level role implicitly holds all inherited lower-level roles. diff --git a/descriptions/edges/GH_HasBranch.md b/descriptions/edges/GH_HasBranch.md index 6cde74f..b65366a 100644 --- a/descriptions/edges/GH_HasBranch.md +++ b/descriptions/edges/GH_HasBranch.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_HasBranch` edge represents the relationship between a repository and its branches. Created by `Git-HoundBranch`, this edge links each collected branch to its parent repository. It is a structural edge that provides the foundation for understanding branch-level protections and access controls. While not traversable itself, it connects repositories to branches where traversable edges like `GH_CanWriteBranch` and `GH_CanEditProtection` model the effective access. +The non-traversable GH_HasBranch edge represents the relationship between a repository and its branches. This edge links each collected branch to its parent repository. It is a structural edge that provides the foundation for understanding branch-level protections and access controls. While not traversable itself, it connects repositories to branches where traversable edges like GH_CanWriteBranch and GH_CanEditProtection model the effective access. diff --git a/descriptions/edges/GH_HasEnvironment.md b/descriptions/edges/GH_HasEnvironment.md index e2b6e9a..2f46635 100644 --- a/descriptions/edges/GH_HasEnvironment.md +++ b/descriptions/edges/GH_HasEnvironment.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_HasEnvironment` edge represents the relationship between a repository or branch and its deployment environments. Created by `Git-HoundEnvironment`, this edge links environments to the repositories that define them and to the branches that are allowed to deploy to them (via deployment branch policies). Environments are security-relevant because they can gate access to secrets and cloud credentials, and their deployment branch policies control which branches can trigger deployments. +The non-traversable GH_HasEnvironment edge represents the relationship between a repository or branch and its deployment environments. This edge links environments to the repositories that define them and to the branches that are allowed to deploy to them (via deployment branch policies). Environments are security-relevant because they can gate access to secrets and cloud credentials, and their deployment branch policies control which branches can trigger deployments. diff --git a/descriptions/edges/GH_HasExternalIdentity.md b/descriptions/edges/GH_HasExternalIdentity.md index 24ca725..4aea643 100644 --- a/descriptions/edges/GH_HasExternalIdentity.md +++ b/descriptions/edges/GH_HasExternalIdentity.md @@ -1,3 +1,3 @@ -# General Information +## General Information -The non-traversable `GH_HasExternalIdentity` edge represents the relationship between a SAML identity provider and the external identities (SSO users) it manages. Created by `Git-HoundGraphQlSamlProvider`, this edge links each external identity to the SAML provider that authenticated it. External identities are a key component in cross-platform attack path analysis because they bridge the gap between corporate identity providers and GitHub user accounts via the `GH_MapsToUser` edge. Enumerating external identities reveals which corporate users have linked GitHub accounts and enables mapping from IdP compromise to GitHub access. +The non-traversable GH_HasExternalIdentity edge represents the relationship between a SAML identity provider and the external identities (SSO users) it manages. This edge links each external identity to the SAML provider that authenticated it. External identities are a key component in cross-platform attack path analysis because they bridge the gap between corporate identity providers and GitHub user accounts via the GH_MapsToUser edge. Enumerating external identities reveals which corporate users have linked GitHub accounts and enables mapping from IdP compromise to GitHub access. diff --git a/descriptions/edges/GH_HasJob.md b/descriptions/edges/GH_HasJob.md new file mode 100644 index 0000000..cbfcb0a --- /dev/null +++ b/descriptions/edges/GH_HasJob.md @@ -0,0 +1,3 @@ +## General Information + +The traversable GH_HasJob edge links a workflow to each of its jobs. This edge is the primary structural link for walking from a workflow definition into its execution units. Because jobs can declare environments and permissions, traversing this edge enables analysts to reason about what a workflow can do and where it can deploy. diff --git a/descriptions/edges/GH_HasMember.md b/descriptions/edges/GH_HasMember.md new file mode 100644 index 0000000..660f1bd --- /dev/null +++ b/descriptions/edges/GH_HasMember.md @@ -0,0 +1,3 @@ +## General Information + +The non-traversable GH_HasMember edge represents the relationship between a GitHub enterprise or organization and a user who is a member of that scope. This edge records membership as directory context rather than as an access path: being listed as a member does not by itself describe what the user can do, only that the user belongs to the enterprise or organization. Membership remains security-relevant because it defines the population from which roles, team assignments, and token approvals are drawn, and it helps analysts understand who is inside the trust boundary when reviewing GitHub exposure. diff --git a/descriptions/edges/GH_HasPersonalAccessToken.md b/descriptions/edges/GH_HasPersonalAccessToken.md index 7982d5f..9e340b5 100644 --- a/descriptions/edges/GH_HasPersonalAccessToken.md +++ b/descriptions/edges/GH_HasPersonalAccessToken.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_HasPersonalAccessToken` edge represents the relationship between a user and their fine-grained personal access tokens that have been granted access to the organization. Created by `Git-HoundPersonalAccessToken`, this edge links each approved token back to the user who created it. Fine-grained personal access tokens are security-significant because they provide programmatic access to organization resources with specific scoped permissions. Tracking token ownership is essential for understanding which users have standing API access and for identifying tokens that may need revocation. +The non-traversable GH_HasPersonalAccessToken edge represents the relationship between a user and their fine-grained personal access tokens that have been granted access to the organization. This edge links each approved token back to the user who created it. Fine-grained personal access tokens are security-significant because they provide programmatic access to organization resources with specific scoped permissions. Tracking token ownership is essential for understanding which users have standing API access and for identifying tokens that may need revocation. diff --git a/descriptions/edges/GH_HasPersonalAccessTokenRequest.md b/descriptions/edges/GH_HasPersonalAccessTokenRequest.md index 7ffaa0b..ca85f2b 100644 --- a/descriptions/edges/GH_HasPersonalAccessTokenRequest.md +++ b/descriptions/edges/GH_HasPersonalAccessTokenRequest.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_HasPersonalAccessTokenRequest` edge represents the relationship between a user and their pending personal access token requests awaiting organizational approval. Created by `Git-HoundPersonalAccessTokenRequest`, this edge links each pending token request back to the user who submitted it. Pending token requests are security-relevant because they represent access that may soon be granted, and reviewing them helps administrators understand what permissions users are requesting before approval. Organizations that require approval for fine-grained PATs will have these requests queued until an administrator acts on them. +The non-traversable GH_HasPersonalAccessTokenRequest edge represents the relationship between a user and their pending personal access token requests awaiting organizational approval. This edge links each pending token request back to the user who submitted it. Pending token requests are security-relevant because they represent access that may soon be granted, and reviewing them helps administrators understand what permissions users are requesting before approval. Organizations that require approval for fine-grained PATs will have these requests queued until an administrator acts on them. diff --git a/descriptions/edges/GH_HasRole.md b/descriptions/edges/GH_HasRole.md index cd6c268..38a030a 100644 --- a/descriptions/edges/GH_HasRole.md +++ b/descriptions/edges/GH_HasRole.md @@ -1,3 +1,3 @@ ## General Information -The traversable `GH_HasRole` edge represents the assignment of a user or team to a specific role within the organization, repository, or team. This is the primary edge for connecting identities to their permissions and serves as the foundation of all access paths in the GitHub permission model. It is created by `Git-HoundUser` (for org roles), `Git-HoundRepositoryRole` (for repo roles), and `Git-HoundTeam` (for team roles). Because role assignment is the starting point for determining what a principal can do, this edge is traversable and critical for attack path analysis. +The traversable GH_HasRole edge represents the assignment of a user or team to a specific role within the organization, repository, or team. This is the primary edge for connecting identities to their permissions and serves as the foundation of all access paths in the GitHub permission model. Because role assignment is the starting point for determining what a principal can do, this edge is traversable and critical for attack path analysis. diff --git a/descriptions/edges/GH_HasSamlIdentityProvider.md b/descriptions/edges/GH_HasSamlIdentityProvider.md index 6206c33..0ae7fd7 100644 --- a/descriptions/edges/GH_HasSamlIdentityProvider.md +++ b/descriptions/edges/GH_HasSamlIdentityProvider.md @@ -1,3 +1,3 @@ -# General Information +## General Information -The non-traversable `GH_HasSamlIdentityProvider` edge represents the relationship between an organization and its SAML identity provider configuration. Created by `Git-HoundGraphQlSamlProvider`, this edge links an organization to the SAML SSO provider used for authentication and user provisioning. SAML identity providers are a critical security component because they establish the trust boundary between an external identity provider (such as Entra ID or Okta) and the GitHub organization. Understanding this relationship is essential for mapping cross-platform attack paths where compromise of the identity provider could lead to access within the GitHub organization. +The non-traversable GH_HasSamlIdentityProvider edge represents the relationship between an organization and its SAML identity provider configuration. This edge links an organization to the SAML SSO provider used for authentication and user provisioning. SAML identity providers are a critical security component because they establish the trust boundary between an external identity provider (such as Entra ID or Okta) and the GitHub organization. Understanding this relationship is essential for mapping cross-platform attack paths where compromise of the identity provider could lead to access within the GitHub organization. diff --git a/descriptions/edges/GH_HasSecret.md b/descriptions/edges/GH_HasSecret.md index 5780d58..7bf1cac 100644 --- a/descriptions/edges/GH_HasSecret.md +++ b/descriptions/edges/GH_HasSecret.md @@ -1,3 +1,3 @@ ## General Information -The traversable `GH_HasSecret` edge represents the relationship between a repository or environment and the secrets accessible within that context. Created by `Git-HoundOrganizationSecret`, `Git-HoundSecret`, and `Git-HoundEnvironment`, this edge shows which secrets are available in which scopes. Repositories can have access to both organization-level secrets (scoped to selected repositories) and repository-level secrets, while environments contain their own environment-scoped secrets. This edge is traversable because any principal that can push code to a repository (via `GH_CanWriteBranch` or `GH_CanCreateBranch`) can write a workflow that exfiltrates the secret values at runtime, making this a meaningful link in attack path analysis. +The traversable GH_HasSecret edge represents the relationship between a repository or environment and the secrets accessible within that context. This edge shows which secrets are available in which scopes. Repositories can have access to both organization-level secrets (scoped to selected repositories) and repository-level secrets, while environments contain their own environment-scoped secrets. This edge is traversable because any principal that can push code to a repository (via GH_CanWriteBranch or GH_CanCreateBranch) can write a workflow that exfiltrates the secret values at runtime, making this a meaningful link in attack path analysis. diff --git a/descriptions/edges/GH_HasStep.md b/descriptions/edges/GH_HasStep.md new file mode 100644 index 0000000..1664dad --- /dev/null +++ b/descriptions/edges/GH_HasStep.md @@ -0,0 +1,3 @@ +## General Information + +The traversable GH_HasStep edge links a job to each of its steps in execution order. This edge enables analysts to enumerate all actions and shell commands executed by a job, including which secrets and variables each step consumes. diff --git a/descriptions/edges/GH_HasVariable.md b/descriptions/edges/GH_HasVariable.md index 8a62f5d..bf7061f 100644 --- a/descriptions/edges/GH_HasVariable.md +++ b/descriptions/edges/GH_HasVariable.md @@ -1,3 +1,3 @@ ## General Information -The traversable `GH_HasVariable` edge represents the relationship between a repository and the variables accessible within that context. Created by `Git-HoundOrganizationSecret` and `Git-HoundVariable`, this edge shows which variables are available in which scopes. Repositories can have access to both organization-level variables (scoped by visibility to all, private, or selected repositories) and repository-level variables defined directly on the repo. This edge is traversable because any principal that can push code to a repository (via `GH_CanWriteBranch` or `GH_CanCreateBranch`) can write a workflow that reads variable values at runtime, and variables may contain configuration data useful for lateral movement such as deployment URLs, service names, or environment identifiers. +The traversable GH_HasVariable edge represents the relationship between a repository and the variables accessible within that context. This edge shows which variables are available in which scopes. Repositories can have access to both organization-level variables (scoped by visibility to all, private, or selected repositories) and repository-level variables defined directly on the repo. This edge is traversable because any principal that can push code to a repository (via GH_CanWriteBranch or GH_CanCreateBranch) can write a workflow that reads variable values at runtime, and variables may contain configuration data useful for lateral movement such as deployment URLs, service names, or environment identifiers. diff --git a/descriptions/edges/GH_HasWorkflow.md b/descriptions/edges/GH_HasWorkflow.md index 80f80f1..8ec759e 100644 --- a/descriptions/edges/GH_HasWorkflow.md +++ b/descriptions/edges/GH_HasWorkflow.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_HasWorkflow` edge represents the relationship between a repository and its GitHub Actions workflows. Created by `Git-HoundWorkflow`, this edge links each discovered workflow definition to its parent repository. Workflows are significant from a security perspective because they can execute arbitrary code with repository permissions, access secrets, and assume cloud identities. This structural edge enables analysts to enumerate which workflows exist in a given repository. +The non-traversable GH_HasWorkflow edge represents the relationship between a repository and its GitHub Actions workflows. This edge links each discovered workflow definition to its parent repository. Workflows are significant from a security perspective because they can execute arbitrary code with repository permissions, access secrets, and assume cloud identities. This structural edge enables analysts to enumerate which workflows exist in a given repository. diff --git a/descriptions/edges/GH_InstalledAs.md b/descriptions/edges/GH_InstalledAs.md index ec16e5b..8c49d68 100644 --- a/descriptions/edges/GH_InstalledAs.md +++ b/descriptions/edges/GH_InstalledAs.md @@ -1,3 +1,3 @@ ## General Information -The traversable `GH_InstalledAs` edge links a GitHub App to its installation within the organization. It is created by `Git-HoundAppInstallation` during app installation enumeration. This edge is traversable because it connects the app definition to its active installation, which determines the specific set of repositories and permissions the app has been granted. Understanding the relationship between an app and its installation is essential for tracing how app-level permissions translate into repository access. +The traversable GH_InstalledAs edge links a GitHub App to its installation within the organization. This edge is traversable because it connects the app definition to its active installation, which determines the specific set of repositories and permissions the app has been granted. Understanding the relationship between an app and its installation is essential for tracing how app-level permissions translate into repository access. diff --git a/descriptions/edges/GH_InviteMember.md b/descriptions/edges/GH_InviteMember.md index 7e620b9..75bf35c 100644 --- a/descriptions/edges/GH_InviteMember.md +++ b/descriptions/edges/GH_InviteMember.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_InviteMember` edge represents that a role has the ability to invite new members to the organization. This permission is typically restricted to Owners, as inviting members expands the organization's trust boundary by granting new users access to internal resources. An attacker with this permission could invite a controlled account to gain persistent access to the organization's repositories, teams, and secrets. +The non-traversable GH_InviteMember edge represents that a role has the ability to invite new members to the organization. This permission is typically restricted to Owners, as inviting members expands the organization's trust boundary by granting new users access to internal resources. An attacker with this permission could invite a controlled account to gain persistent access to the organization's repositories, teams, and secrets. diff --git a/descriptions/edges/GH_JumpMergeQueue.md b/descriptions/edges/GH_JumpMergeQueue.md index 2fffb3b..f061ed6 100644 --- a/descriptions/edges/GH_JumpMergeQueue.md +++ b/descriptions/edges/GH_JumpMergeQueue.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_JumpMergeQueue` edge represents a role's ability to jump ahead of other entries in the merge queue. This permission is available to Admin roles and custom roles that have been granted this specific permission. Merge queues enforce an ordered sequence of CI checks and merges; jumping the queue allows a principal to prioritize their changes ahead of others. While less severe than bypassing protections entirely, this permission can be used to accelerate the landing of malicious changes before other queued entries are reviewed or tested. +The non-traversable GH_JumpMergeQueue edge represents a role's ability to jump ahead of other entries in the merge queue. This permission is available to Admin roles and custom roles that have been granted this specific permission. Merge queues enforce an ordered sequence of CI checks and merges; jumping the queue allows a principal to prioritize their changes ahead of others. While less severe than bypassing protections entirely, this permission can be used to accelerate the landing of malicious changes before other queued entries are reviewed or tested. diff --git a/descriptions/edges/GH_ManageDeployKeys.md b/descriptions/edges/GH_ManageDeployKeys.md index 7a7149c..5c8759e 100644 --- a/descriptions/edges/GH_ManageDeployKeys.md +++ b/descriptions/edges/GH_ManageDeployKeys.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ManageDeployKeys` edge represents a role's ability to create, modify, and delete deploy keys for the repository. This permission is available to Admin roles and custom roles that have been granted this specific permission. Deploy keys provide SSH-based access to the repository, and a deploy key with write access can push commits directly without going through the GitHub web interface or API authentication. Managing deploy keys is security-significant because it enables the creation of persistent, credential-based access that operates outside the normal user authentication flow. +The non-traversable GH_ManageDeployKeys edge represents a role's ability to create, modify, and delete deploy keys for the repository. This permission is available to Admin roles and custom roles that have been granted this specific permission. Deploy keys provide SSH-based access to the repository, and a deploy key with write access can push commits directly without going through the GitHub web interface or API authentication. Managing deploy keys is security-significant because it enables the creation of persistent, credential-based access that operates outside the normal user authentication flow. diff --git a/descriptions/edges/GH_ManageDiscussionBadges.md b/descriptions/edges/GH_ManageDiscussionBadges.md index 9f91e71..796d7de 100644 --- a/descriptions/edges/GH_ManageDiscussionBadges.md +++ b/descriptions/edges/GH_ManageDiscussionBadges.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ManageDiscussionBadges` edge represents a role's ability to manage discussion badges used to highlight discussion participants. This permission is available to Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_ManageDiscussionBadges edge represents a role's ability to manage discussion badges used to highlight discussion participants. This permission is available to Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_ManageOrganizationWebhooks.md b/descriptions/edges/GH_ManageOrganizationWebhooks.md index 969c63a..d3a282c 100644 --- a/descriptions/edges/GH_ManageOrganizationWebhooks.md +++ b/descriptions/edges/GH_ManageOrganizationWebhooks.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ManageOrganizationWebhooks` edge represents that a role has the ability to manage organization-level webhooks. This edge is dynamically generated from custom organization role permissions discovered by the collector. Webhooks can be configured to send event data to external endpoints, making this permission significant for security because an attacker could create or modify webhooks to exfiltrate repository data, commit contents, or issue details to an attacker-controlled server, or use them as a persistence mechanism. +The non-traversable GH_ManageOrganizationWebhooks edge represents that a role has the ability to manage organization-level webhooks. This edge is dynamically generated from custom organization role permissions discovered by the collector. Webhooks can be configured to send event data to external endpoints, making this permission significant for security because an attacker could create or modify webhooks to exfiltrate repository data, commit contents, or issue details to an attacker-controlled server, or use them as a persistence mechanism. diff --git a/descriptions/edges/GH_ManageRepoSecurityProducts.md b/descriptions/edges/GH_ManageRepoSecurityProducts.md index e4a3e0d..43f8ae7 100644 --- a/descriptions/edges/GH_ManageRepoSecurityProducts.md +++ b/descriptions/edges/GH_ManageRepoSecurityProducts.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ManageRepoSecurityProducts` edge represents a role's ability to manage repository-specific security product settings. This permission is available to Admin roles and custom roles that have been granted this specific permission. Unlike the broader `GH_ManageSecurityProducts` permission, this edge is scoped to repository-level security configuration such as repository-specific scanning settings and alert management. Disabling repository-level security products can create blind spots in vulnerability detection for the specific repository. +The non-traversable GH_ManageRepoSecurityProducts edge represents a role's ability to manage repository-specific security product settings. This permission is available to Admin roles and custom roles that have been granted this specific permission. Unlike the broader GH_ManageSecurityProducts permission, this edge is scoped to repository-level security configuration such as repository-specific scanning settings and alert management. Disabling repository-level security products can create blind spots in vulnerability detection for the specific repository. diff --git a/descriptions/edges/GH_ManageSecurityProducts.md b/descriptions/edges/GH_ManageSecurityProducts.md index 213fbc0..4d4d314 100644 --- a/descriptions/edges/GH_ManageSecurityProducts.md +++ b/descriptions/edges/GH_ManageSecurityProducts.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ManageSecurityProducts` edge represents a role's ability to manage security product settings on the repository. This permission is available to Admin roles and custom roles that have been granted this specific permission. Managing security products allows enabling or disabling features such as secret scanning, code scanning, and Dependabot alerts. An attacker with this permission could disable security features to prevent detection of vulnerabilities or leaked secrets, making this a high-severity permission for security posture management. +The non-traversable GH_ManageSecurityProducts edge represents a role's ability to manage security product settings on the repository. This permission is available to Admin roles and custom roles that have been granted this specific permission. Managing security products allows enabling or disabling features such as secret scanning, code scanning, and Dependabot alerts. An attacker with this permission could disable security features to prevent detection of vulnerabilities or leaked secrets, making this a high-severity permission for security posture management. diff --git a/descriptions/edges/GH_ManageSettingsMergeTypes.md b/descriptions/edges/GH_ManageSettingsMergeTypes.md index cf64017..c01a792 100644 --- a/descriptions/edges/GH_ManageSettingsMergeTypes.md +++ b/descriptions/edges/GH_ManageSettingsMergeTypes.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ManageSettingsMergeTypes` edge represents a role's ability to configure allowed merge types (merge commit, squash, rebase) on the repository. This permission is available to Maintain and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_ManageSettingsMergeTypes edge represents a role's ability to configure allowed merge types (merge commit, squash, rebase) on the repository. This permission is available to Maintain and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_ManageSettingsPages.md b/descriptions/edges/GH_ManageSettingsPages.md index e826cff..c669771 100644 --- a/descriptions/edges/GH_ManageSettingsPages.md +++ b/descriptions/edges/GH_ManageSettingsPages.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ManageSettingsPages` edge represents a role's ability to manage GitHub Pages settings including enabling, disabling, and configuring the source. This permission is available to Maintain and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_ManageSettingsPages edge represents a role's ability to manage GitHub Pages settings including enabling, disabling, and configuring the source. This permission is available to Maintain and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_ManageSettingsProjects.md b/descriptions/edges/GH_ManageSettingsProjects.md index e41206e..0a06e55 100644 --- a/descriptions/edges/GH_ManageSettingsProjects.md +++ b/descriptions/edges/GH_ManageSettingsProjects.md @@ -1,3 +1,3 @@ -# General Information +## General Information -The non-traversable `GH_ManageSettingsProjects` edge represents a role's ability to manage project board settings on the repository. This permission is available to Maintain and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_ManageSettingsProjects edge represents a role's ability to manage project board settings on the repository. This permission is available to Maintain and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_ManageSettingsWiki.md b/descriptions/edges/GH_ManageSettingsWiki.md index 73a2e88..97756cb 100644 --- a/descriptions/edges/GH_ManageSettingsWiki.md +++ b/descriptions/edges/GH_ManageSettingsWiki.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ManageSettingsWiki` edge represents a role's ability to enable or disable the repository wiki. This permission is available to Maintain and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_ManageSettingsWiki edge represents a role's ability to enable or disable the repository wiki. This permission is available to Maintain and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_ManageTopics.md b/descriptions/edges/GH_ManageTopics.md index 0ca7330..191096a 100644 --- a/descriptions/edges/GH_ManageTopics.md +++ b/descriptions/edges/GH_ManageTopics.md @@ -1,3 +1,3 @@ -# General Information +## General Information -The non-traversable `GH_ManageTopics` edge represents a role's ability to manage repository topics used for discovery and classification. This permission is available to Maintain and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_ManageTopics edge represents a role's ability to manage repository topics used for discovery and classification. This permission is available to Maintain and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_ManageWebhooks.md b/descriptions/edges/GH_ManageWebhooks.md index 84bfa3a..e2d9e4c 100644 --- a/descriptions/edges/GH_ManageWebhooks.md +++ b/descriptions/edges/GH_ManageWebhooks.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ManageWebhooks` edge represents a role's ability to create, modify, and delete repository-level webhooks. This permission is available to Admin roles and custom roles that have been granted this specific permission. Webhooks can exfiltrate repository events and code changes to external endpoints, making this a security-sensitive permission. An attacker with this permission could configure a webhook to receive push event payloads containing commit diffs, effectively creating a covert channel for data exfiltration. +The non-traversable GH_ManageWebhooks edge represents a role's ability to create, modify, and delete repository-level webhooks. This permission is available to Admin roles and custom roles that have been granted this specific permission. Webhooks can exfiltrate repository events and code changes to external endpoints, making this a security-sensitive permission. An attacker with this permission could configure a webhook to receive push event payloads containing commit diffs, effectively creating a covert channel for data exfiltration. diff --git a/descriptions/edges/GH_MapsToUser.md b/descriptions/edges/GH_MapsToUser.md index 935cc95..5e785eb 100644 --- a/descriptions/edges/GH_MapsToUser.md +++ b/descriptions/edges/GH_MapsToUser.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_MapsToUser` edge maps an external identity (provisioned via SAML or SCIM) to a GitHub user within the organization, or to an external IdP user (such as AZUser, OktaUser, or PingOneUser) in hybrid graph scenarios. It is created by `Git-HoundGraphQlSamlProvider` for SAML-linked identities and `Git-HoundScimUser` for SCIM-provisioned identities. This edge represents identity correlation rather than an attack path, connecting a user's external IdP account to their GitHub account for visibility into federated identity mappings. +The non-traversable GH_MapsToUser edge maps an external identity (provisioned via SAML or SCIM) to a GitHub user within the organization, or to an external IdP user (such as [AZUser](https://bloodhound.specterops.io/resources/nodes/az-user), [Okta_User](https://bloodhound.specterops.io/opengraph/extensions/okta/nodes/okta_user), or [PingOneUser](https://github.com/andyrobbins/PingOneHound?tab=readme-ov-file#schema)) in hybrid graph scenarios. This edge represents identity correlation rather than an attack path, connecting a user's external IdP account to their GitHub account for visibility into federated identity mappings. diff --git a/descriptions/edges/GH_MarkAsDuplicate.md b/descriptions/edges/GH_MarkAsDuplicate.md index 6ed4117..fc78807 100644 --- a/descriptions/edges/GH_MarkAsDuplicate.md +++ b/descriptions/edges/GH_MarkAsDuplicate.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_MarkAsDuplicate` edge represents a role's ability to mark issues or pull requests as duplicates. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_MarkAsDuplicate edge represents a role's ability to mark issues or pull requests as duplicates. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_MemberOf.md b/descriptions/edges/GH_MemberOf.md index 70fddb9..f6e3ca5 100644 --- a/descriptions/edges/GH_MemberOf.md +++ b/descriptions/edges/GH_MemberOf.md @@ -1,3 +1,3 @@ ## General Information -The traversable `GH_MemberOf` edge represents team membership, linking a team role to its parent team or a child team to a parent team in nested team hierarchies. It is created by `Git-HoundTeam` during team enumeration. This edge is traversable because team membership extends access transitively -- a user who holds a role in a child team inherits the repository permissions of all ancestor teams in the nesting hierarchy, making it a key component of attack path analysis. +The traversable GH_MemberOf edge represents team membership, linking a team role to its parent team or a child team to a parent team in nested team hierarchies. This edge is traversable because team membership extends access transitively -- a user who holds a role in a child team inherits the repository permissions of all ancestor teams in the nesting hierarchy, making it a key component of attack path analysis. diff --git a/descriptions/edges/GH_OrgBypassCodeScanningDismissalRequests.md b/descriptions/edges/GH_OrgBypassCodeScanningDismissalRequests.md index ac43501..47a213d 100644 --- a/descriptions/edges/GH_OrgBypassCodeScanningDismissalRequests.md +++ b/descriptions/edges/GH_OrgBypassCodeScanningDismissalRequests.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_OrgBypassCodeScanningDismissalRequests` edge represents that a role can bypass code scanning dismissal requests at the organization level. This edge is dynamically generated from custom organization role permissions discovered by the collector. This permission allows suppressing code scanning security findings without the standard review process, which is significant because an attacker could use it to hide vulnerabilities or malicious code patterns that would otherwise be flagged by automated scanning tools. +The non-traversable GH_OrgBypassCodeScanningDismissalRequests edge represents that a role can bypass code scanning dismissal requests at the organization level. This edge is dynamically generated from custom organization role permissions discovered by the collector. This permission allows suppressing code scanning security findings without the standard review process, which is significant because an attacker could use it to hide vulnerabilities or malicious code patterns that would otherwise be flagged by automated scanning tools. diff --git a/descriptions/edges/GH_OrgBypassSecretScanningClosureRequests.md b/descriptions/edges/GH_OrgBypassSecretScanningClosureRequests.md index e21538b..ae2dc37 100644 --- a/descriptions/edges/GH_OrgBypassSecretScanningClosureRequests.md +++ b/descriptions/edges/GH_OrgBypassSecretScanningClosureRequests.md @@ -1,3 +1,3 @@ -# General Information +## General Information -The non-traversable `GH_OrgBypassSecretScanningClosureRequests` edge represents that a role can bypass secret scanning closure requests at the organization level. This edge is dynamically generated from custom organization role permissions discovered by the collector. This permission allows closing secret scanning alerts without going through the standard review and approval process, which is significant because an attacker could use it to suppress alerts about leaked credentials and prevent incident response teams from being notified. +The non-traversable GH_OrgBypassSecretScanningClosureRequests edge represents that a role can bypass secret scanning closure requests at the organization level. This edge is dynamically generated from custom organization role permissions discovered by the collector. This permission allows closing secret scanning alerts without going through the standard review and approval process, which is significant because an attacker could use it to suppress alerts about leaked credentials and prevent incident response teams from being notified. diff --git a/descriptions/edges/GH_OrgReviewAndManageSecretScanningBypassRequests.md b/descriptions/edges/GH_OrgReviewAndManageSecretScanningBypassRequests.md index c41a80d..a2623dc 100644 --- a/descriptions/edges/GH_OrgReviewAndManageSecretScanningBypassRequests.md +++ b/descriptions/edges/GH_OrgReviewAndManageSecretScanningBypassRequests.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_OrgReviewAndManageSecretScanningBypassRequests` edge represents that a role can review and manage secret scanning push protection bypass requests at the organization level. This edge is dynamically generated from custom organization role permissions discovered by the collector. Push protection prevents secrets from being committed to repositories, and bypass requests allow developers to override this protection for specific commits. An attacker with this permission could approve their own or an accomplice's bypass requests, allowing secrets to be committed to repositories without triggering push protection blocks. +The non-traversable GH_OrgReviewAndManageSecretScanningBypassRequests edge represents that a role can review and manage secret scanning push protection bypass requests at the organization level. This edge is dynamically generated from custom organization role permissions discovered by the collector. Push protection prevents secrets from being committed to repositories, and bypass requests allow developers to override this protection for specific commits. An attacker with this permission could approve their own or an accomplice's bypass requests, allowing secrets to be committed to repositories without triggering push protection blocks. diff --git a/descriptions/edges/GH_OrgReviewAndManageSecretScanningClosureRequests.md b/descriptions/edges/GH_OrgReviewAndManageSecretScanningClosureRequests.md index 45c276f..db4466c 100644 --- a/descriptions/edges/GH_OrgReviewAndManageSecretScanningClosureRequests.md +++ b/descriptions/edges/GH_OrgReviewAndManageSecretScanningClosureRequests.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_OrgReviewAndManageSecretScanningClosureRequests` edge represents that a role can review and manage secret scanning alert closure requests at the organization level. This edge is dynamically generated from custom organization role permissions discovered by the collector. Alert closure requests are part of the workflow for closing secret scanning alerts, and this permission controls who can approve or deny those requests. An attacker with this permission could approve closure requests to suppress alerts about actively leaked credentials, undermining the organization's secret scanning remediation process. +The non-traversable GH_OrgReviewAndManageSecretScanningClosureRequests edge represents that a role can review and manage secret scanning alert closure requests at the organization level. This edge is dynamically generated from custom organization role permissions discovered by the collector. Alert closure requests are part of the workflow for closing secret scanning alerts, and this permission controls who can approve or deny those requests. An attacker with this permission could approve closure requests to suppress alerts about actively leaked credentials, undermining the organization's secret scanning remediation process. diff --git a/descriptions/edges/GH_Owns.md b/descriptions/edges/GH_Owns.md index 95a3ff5..bedd056 100644 --- a/descriptions/edges/GH_Owns.md +++ b/descriptions/edges/GH_Owns.md @@ -1,3 +1,3 @@ ## General Information -The traversable `GH_Owns` edge represents that an organization owns a repository. Created by `Git-HoundRepository`, this edge establishes the foundation of the access control model by linking repositories to their owning organization. It is traversable because repository ownership is a critical relationship for understanding how organizational permissions cascade down to repository-level access, making it essential for attack path analysis. +The traversable GH_Owns edge represents that an organization owns a repository. This edge establishes the foundation of the access control model by linking repositories to their owning organization. It is traversable because repository ownership is a critical relationship for understanding how organizational permissions cascade down to repository-level access, making it essential for attack path analysis. diff --git a/descriptions/edges/GH_ProtectedBy.md b/descriptions/edges/GH_ProtectedBy.md index ba21050..3c81dbd 100644 --- a/descriptions/edges/GH_ProtectedBy.md +++ b/descriptions/edges/GH_ProtectedBy.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ProtectedBy` edge represents that a branch protection rule applies to a specific branch. Created by `Git-HoundBranch` when branch protection rules are collected, this edge links protection rules to the branches they govern. Understanding which protections apply to a branch is critical for determining the effective access model — protections such as required reviews, status checks, and push restrictions directly impact who can modify a branch. This edge is consumed by the computed edge functions (`Compute-GitHoundBranchAccess`) to determine effective push access; the computed `GH_CanWriteBranch` and `GH_CanEditProtection` edges carry traversability instead. +The non-traversable GH_ProtectedBy edge represents that a branch protection rule applies to a specific branch. This edge links protection rules to the branches they govern. Understanding which protections apply to a branch is critical for determining the effective access model — protections such as required reviews, status checks, and push restrictions directly impact who can modify a branch. This edge is consumed by the computed branch-access edges to determine effective push access; the computed GH_CanWriteBranch and GH_CanEditProtection edges carry traversability instead. diff --git a/descriptions/edges/GH_PushProtectedBranch.md b/descriptions/edges/GH_PushProtectedBranch.md index edee54d..26ba504 100644 --- a/descriptions/edges/GH_PushProtectedBranch.md +++ b/descriptions/edges/GH_PushProtectedBranch.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_PushProtectedBranch` edge represents a role's ability to push directly to branches that are protected by push restrictions. This permission is available to Admin and Maintain roles. This edge bypasses the push gate of branch protection, allowing direct commits to protected branches without going through the pull request workflow. Unlike merge gate bypasses (such as `GH_BypassBranchProtection`), this push gate bypass is NOT suppressed by the `enforce_admins` setting on the branch protection rule, making it a particularly potent permission. +The non-traversable GH_PushProtectedBranch edge represents a role's ability to push directly to branches that are protected by push restrictions. This permission is available to Admin and Maintain roles. This edge bypasses the push gate of branch protection, allowing direct commits to protected branches without going through the pull request workflow. Unlike merge gate bypasses (such as GH_BypassBranchProtection), this push gate bypass is NOT suppressed by the `enforce_admins` setting on the branch protection rule, making it a particularly potent permission. diff --git a/descriptions/edges/GH_ReadCodeScanning.md b/descriptions/edges/GH_ReadCodeScanning.md index 9931ba0..ab0ece3 100644 --- a/descriptions/edges/GH_ReadCodeScanning.md +++ b/descriptions/edges/GH_ReadCodeScanning.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ReadCodeScanning` edge represents a role's ability to read code scanning analysis results and alerts. This permission is available to Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. Code scanning alerts may reveal exploitable vulnerabilities in the codebase. +The non-traversable GH_ReadCodeScanning edge represents a role's ability to read code scanning analysis results and alerts. This permission is available to Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. Code scanning alerts may reveal exploitable vulnerabilities in the codebase. diff --git a/descriptions/edges/GH_ReadOrganizationActionsUsageMetrics.md b/descriptions/edges/GH_ReadOrganizationActionsUsageMetrics.md index 85d25b0..53abbb1 100644 --- a/descriptions/edges/GH_ReadOrganizationActionsUsageMetrics.md +++ b/descriptions/edges/GH_ReadOrganizationActionsUsageMetrics.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ReadOrganizationActionsUsageMetrics` edge represents that a role can read GitHub Actions usage metrics for the organization. This edge is dynamically generated from custom organization role permissions discovered by the collector. Usage metrics provide visibility into workflow execution patterns, runner utilization, and billing data across the organization. While this is primarily an informational permission, it can reveal which repositories have active CI/CD pipelines and the scale of automation in use. +The non-traversable GH_ReadOrganizationActionsUsageMetrics edge represents that a role can read GitHub Actions usage metrics for the organization. This edge is dynamically generated from custom organization role permissions discovered by the collector. Usage metrics provide visibility into workflow execution patterns, runner utilization, and billing data across the organization. While this is primarily an informational permission, it can reveal which repositories have active CI/CD pipelines and the scale of automation in use. diff --git a/descriptions/edges/GH_ReadOrganizationCustomOrgRole.md b/descriptions/edges/GH_ReadOrganizationCustomOrgRole.md index dc8a2c1..4d44593 100644 --- a/descriptions/edges/GH_ReadOrganizationCustomOrgRole.md +++ b/descriptions/edges/GH_ReadOrganizationCustomOrgRole.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ReadOrganizationCustomOrgRole` edge represents that a role can read custom organization role definitions. This edge is dynamically generated from custom organization role permissions discovered by the collector. Reading custom org role definitions allows a user to enumerate the permissions granted to each custom role, which provides reconnaissance value for understanding the organization's access control model and identifying roles with elevated privileges. +The non-traversable GH_ReadOrganizationCustomOrgRole edge represents that a role can read custom organization role definitions. This edge is dynamically generated from custom organization role permissions discovered by the collector. Reading custom org role definitions allows a user to enumerate the permissions granted to each custom role, which provides reconnaissance value for understanding the organization's access control model and identifying roles with elevated privileges. diff --git a/descriptions/edges/GH_ReadOrganizationCustomRepoRole.md b/descriptions/edges/GH_ReadOrganizationCustomRepoRole.md index 630967f..347cbcd 100644 --- a/descriptions/edges/GH_ReadOrganizationCustomRepoRole.md +++ b/descriptions/edges/GH_ReadOrganizationCustomRepoRole.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ReadOrganizationCustomRepoRole` edge represents that a role can read custom repository role definitions. This edge is dynamically generated from custom organization role permissions discovered by the collector. Reading custom repo role definitions allows a user to enumerate the permissions granted to each custom repository role, which provides reconnaissance value for understanding repository-level access controls and identifying roles that grant elevated repository permissions. +The non-traversable GH_ReadOrganizationCustomRepoRole edge represents that a role can read custom repository role definitions. This edge is dynamically generated from custom organization role permissions discovered by the collector. Reading custom repo role definitions allows a user to enumerate the permissions granted to each custom repository role, which provides reconnaissance value for understanding repository-level access controls and identifying roles that grant elevated repository permissions. diff --git a/descriptions/edges/GH_ReadRepoContents.md b/descriptions/edges/GH_ReadRepoContents.md index 233e67f..ecc4dfd 100644 --- a/descriptions/edges/GH_ReadRepoContents.md +++ b/descriptions/edges/GH_ReadRepoContents.md @@ -1,7 +1,3 @@ ---- -kind: GH_ReadRepoContents -is_traversable: false ---- ## General Information -The non-traversable `GH_ReadRepoContents` edge represents a role's ability to read repository contents including source code, issues, and pull requests. This is the base level of repository access, available to all roles at the Read permission level and above (Read, Triage, Write, Maintain, Admin). +The non-traversable GH_ReadRepoContents edge represents a role's ability to read repository contents including source code, issues, and pull requests. This is the base level of repository access, available to all roles at the Read permission level and above (Read, Triage, Write, Maintain, Admin). diff --git a/descriptions/edges/GH_RemoveAssignee.md b/descriptions/edges/GH_RemoveAssignee.md index 10d53d6..4cdf99a 100644 --- a/descriptions/edges/GH_RemoveAssignee.md +++ b/descriptions/edges/GH_RemoveAssignee.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_RemoveAssignee` edge represents a role's ability to remove assignees from issues and pull requests. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_RemoveAssignee edge represents a role's ability to remove assignees from issues and pull requests. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_RemoveLabel.md b/descriptions/edges/GH_RemoveLabel.md index 1638801..b46799d 100644 --- a/descriptions/edges/GH_RemoveLabel.md +++ b/descriptions/edges/GH_RemoveLabel.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_RemoveLabel` edge represents a role's ability to remove labels from issues and pull requests. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_RemoveLabel edge represents a role's ability to remove labels from issues and pull requests. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_ReopenDiscussion.md b/descriptions/edges/GH_ReopenDiscussion.md index 0d254fc..8bef672 100644 --- a/descriptions/edges/GH_ReopenDiscussion.md +++ b/descriptions/edges/GH_ReopenDiscussion.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ReopenDiscussion` edge represents a role's ability to reopen closed discussions to allow further replies. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_ReopenDiscussion edge represents a role's ability to reopen closed discussions to allow further replies. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_ReopenIssue.md b/descriptions/edges/GH_ReopenIssue.md index 7f96b3c..5ee1d12 100644 --- a/descriptions/edges/GH_ReopenIssue.md +++ b/descriptions/edges/GH_ReopenIssue.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ReopenIssue` edge represents a role's ability to reopen closed issues. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_ReopenIssue edge represents a role's ability to reopen closed issues. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_ReopenPullRequest.md b/descriptions/edges/GH_ReopenPullRequest.md index 5dd7979..7d1a47f 100644 --- a/descriptions/edges/GH_ReopenPullRequest.md +++ b/descriptions/edges/GH_ReopenPullRequest.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ReopenPullRequest` edge represents a role's ability to reopen closed pull requests. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_ReopenPullRequest edge represents a role's ability to reopen closed pull requests. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_RequestPrReview.md b/descriptions/edges/GH_RequestPrReview.md index 812a458..fed1b81 100644 --- a/descriptions/edges/GH_RequestPrReview.md +++ b/descriptions/edges/GH_RequestPrReview.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_RequestPrReview` edge represents a role's ability to request pull request reviews from specific users or teams. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_RequestPrReview edge represents a role's ability to request pull request reviews from specific users or teams. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_ResolveDependabotAlerts.md b/descriptions/edges/GH_ResolveDependabotAlerts.md index 2a23443..a7d56ee 100644 --- a/descriptions/edges/GH_ResolveDependabotAlerts.md +++ b/descriptions/edges/GH_ResolveDependabotAlerts.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ResolveDependabotAlerts` edge represents a role's ability to dismiss or resolve Dependabot alerts. This permission is available to Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. An attacker could dismiss valid alerts to suppress vulnerability warnings and prevent remediation. +The non-traversable GH_ResolveDependabotAlerts edge represents a role's ability to dismiss or resolve Dependabot alerts. This permission is available to Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. An attacker could dismiss valid alerts to suppress vulnerability warnings and prevent remediation. diff --git a/descriptions/edges/GH_ResolveSecretScanningAlerts.md b/descriptions/edges/GH_ResolveSecretScanningAlerts.md index a95d1b7..1f651ef 100644 --- a/descriptions/edges/GH_ResolveSecretScanningAlerts.md +++ b/descriptions/edges/GH_ResolveSecretScanningAlerts.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ResolveSecretScanningAlerts` edge represents that a role can resolve (close) secret scanning alerts at the organization level. This edge is dynamically generated from custom organization role permissions discovered by the collector. Resolving a secret scanning alert marks a leaked secret as addressed, which removes it from active monitoring dashboards. An attacker with this permission could suppress alerts about leaked credentials to prevent incident response teams from detecting and rotating compromised secrets. +The non-traversable GH_ResolveSecretScanningAlerts edge represents that a role can resolve (close) secret scanning alerts at the organization level. This edge is dynamically generated from custom organization role permissions discovered by the collector. Resolving a secret scanning alert marks a leaked secret as addressed, which removes it from active monitoring dashboards. An attacker with this permission could suppress alerts about leaked credentials to prevent incident response teams from detecting and rotating compromised secrets. diff --git a/descriptions/edges/GH_RestrictionsCanPush.md b/descriptions/edges/GH_RestrictionsCanPush.md index e2434a9..dbbea1b 100644 --- a/descriptions/edges/GH_RestrictionsCanPush.md +++ b/descriptions/edges/GH_RestrictionsCanPush.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_RestrictionsCanPush` edge represents a per-actor allowance that grants push access through push restrictions on a branch protection rule. Created by `Git-HoundBranch` when collecting BPR push allowances, this edge identifies specific users or teams that are permitted to push to the protected branch even when push restrictions are active. This is security-relevant because push restrictions limit who can directly push to a branch, and actors with this allowance bypass that control. Unlike `GH_BypassPullRequestAllowances`, this allowance is NOT suppressed by `enforce_admins` — listed actors retain push access regardless of admin enforcement settings. +The non-traversable GH_RestrictionsCanPush edge represents a per-actor allowance that grants push access through push restrictions on a branch protection rule. This edge identifies specific users or teams that are permitted to push to the protected branch even when push restrictions are active. This is security-relevant because push restrictions limit who can directly push to a branch, and actors with this allowance bypass that control. Unlike GH_BypassPullRequestAllowances, this allowance is NOT suppressed by `enforce_admins` — listed actors retain push access regardless of admin enforcement settings. diff --git a/descriptions/edges/GH_RunOrgMigration.md b/descriptions/edges/GH_RunOrgMigration.md index c8138cc..a9f9b0d 100644 --- a/descriptions/edges/GH_RunOrgMigration.md +++ b/descriptions/edges/GH_RunOrgMigration.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_RunOrgMigration` edge represents a role's ability to run organization migrations on the repository. This permission is available to Admin roles and custom roles that have been granted this specific permission. Organization migrations export repository data including source code, issues, and pull requests, which can be used to transfer repository contents to another organization. This permission is security-relevant because it enables bulk data export from the repository. +The non-traversable GH_RunOrgMigration edge represents a role's ability to run organization migrations on the repository. This permission is available to Admin roles and custom roles that have been granted this specific permission. Organization migrations export repository data including source code, issues, and pull requests, which can be used to transfer repository contents to another organization. This permission is security-relevant because it enables bulk data export from the repository. diff --git a/descriptions/edges/GH_SetInteractionLimits.md b/descriptions/edges/GH_SetInteractionLimits.md index 95a5ae2..608b27a 100644 --- a/descriptions/edges/GH_SetInteractionLimits.md +++ b/descriptions/edges/GH_SetInteractionLimits.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_SetInteractionLimits` edge represents a role's ability to set temporary interaction limits to restrict who can comment, open issues, or create pull requests. This permission is available to Maintain and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_SetInteractionLimits edge represents a role's ability to set temporary interaction limits to restrict who can comment, open issues, or create pull requests. This permission is available to Maintain and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_SetIssueType.md b/descriptions/edges/GH_SetIssueType.md index 0697166..7fb422c 100644 --- a/descriptions/edges/GH_SetIssueType.md +++ b/descriptions/edges/GH_SetIssueType.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_SetIssueType` edge represents a role's ability to set issue types. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_SetIssueType edge represents a role's ability to set issue types. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_SetMilestone.md b/descriptions/edges/GH_SetMilestone.md index 2a236fe..31dcd23 100644 --- a/descriptions/edges/GH_SetMilestone.md +++ b/descriptions/edges/GH_SetMilestone.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_SetMilestone` edge represents a role's ability to set milestones on issues and pull requests. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_SetMilestone edge represents a role's ability to set milestones on issues and pull requests. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_SetSocialPreview.md b/descriptions/edges/GH_SetSocialPreview.md index b1871f1..b8839a5 100644 --- a/descriptions/edges/GH_SetSocialPreview.md +++ b/descriptions/edges/GH_SetSocialPreview.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_SetSocialPreview` edge represents a role's ability to set the repository social preview image shown in link previews. This permission is available to Maintain and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_SetSocialPreview edge represents a role's ability to set the repository social preview image shown in link previews. This permission is available to Maintain and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_SyncedTo.md b/descriptions/edges/GH_SyncedTo.md index e1557d8..4698ce3 100644 --- a/descriptions/edges/GH_SyncedTo.md +++ b/descriptions/edges/GH_SyncedTo.md @@ -1,3 +1,3 @@ ## General Information -The traversable `GH_SyncedTo` edge is a hybrid edge that maps an external IdP user to a GitHub user based on SCIM provisioning. Created by `Git-HoundScimUser` when SCIM data links an external identity to a GitHub account, this edge represents a confirmed identity linkage between an external identity provider and GitHub. It is traversable because compromising the IdP account provides a verified path to the corresponding GitHub account, making it a critical edge for cross-system attack path analysis. This edge enables analysts to trace access from enterprise identity providers like Azure AD, Okta, or PingOne into the GitHub environment. +The traversable GH_SyncedTo edge is a hybrid edge that maps an external IdP user to a GitHub user based on SCIM provisioning. This edge represents a confirmed identity linkage between an external identity provider and GitHub. It is traversable because compromising the IdP account provides a verified path to the corresponding GitHub account, making it a critical edge for cross-system attack path analysis. This edge enables analysts to trace access from enterprise identity providers like Azure AD, Okta, or PingOne into the GitHub environment. diff --git a/descriptions/edges/GH_ToggleDiscussionAnswer.md b/descriptions/edges/GH_ToggleDiscussionAnswer.md index fa32822..fd249a1 100644 --- a/descriptions/edges/GH_ToggleDiscussionAnswer.md +++ b/descriptions/edges/GH_ToggleDiscussionAnswer.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ToggleDiscussionAnswer` edge represents a role's ability to mark or unmark a discussion comment as the accepted answer. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_ToggleDiscussionAnswer edge represents a role's ability to mark or unmark a discussion comment as the accepted answer. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_ToggleDiscussionCommentMinimize.md b/descriptions/edges/GH_ToggleDiscussionCommentMinimize.md index eb41ea8..1df14bb 100644 --- a/descriptions/edges/GH_ToggleDiscussionCommentMinimize.md +++ b/descriptions/edges/GH_ToggleDiscussionCommentMinimize.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ToggleDiscussionCommentMinimize` edge represents a role's ability to minimize or restore discussion comments, hiding them from default view. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. +The non-traversable GH_ToggleDiscussionCommentMinimize edge represents a role's ability to minimize or restore discussion comments, hiding them from default view. This permission is available to Triage, Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. diff --git a/descriptions/edges/GH_TransferRepository.md b/descriptions/edges/GH_TransferRepository.md index a70b090..89b1a1c 100644 --- a/descriptions/edges/GH_TransferRepository.md +++ b/descriptions/edges/GH_TransferRepository.md @@ -1,3 +1,3 @@ -# General Information +## General Information -The non-traversable `GH_TransferRepository` edge represents that a role has the ability to transfer repositories to or from the organization. This permission is typically restricted to Owners, as transferring a repository can move it outside of the organization's security controls, branch protection rules, and audit logging. An attacker with this permission could transfer a repository to an organization they control, effectively exfiltrating the codebase and its associated secrets. +The non-traversable GH_TransferRepository edge represents that a role has the ability to transfer repositories to or from the organization. This permission is typically restricted to Owners, as transferring a repository can move it outside of the organization's security controls, branch protection rules, and audit logging. An attacker with this permission could transfer a repository to an organization they control, effectively exfiltrating the codebase and its associated secrets. diff --git a/descriptions/edges/GH_UsesSecret.md b/descriptions/edges/GH_UsesSecret.md new file mode 100644 index 0000000..2a8b875 --- /dev/null +++ b/descriptions/edges/GH_UsesSecret.md @@ -0,0 +1,19 @@ +## General Information + +The traversable GH_UsesSecret edge links a workflow step to the secret it references via a `${{ secrets.NAME }}` expression. This edge reveals which secrets a step can access at runtime, enabling analysts to trace the blast radius of a compromised workflow. + +### Matching strategy + +Edges use `match_by: property` with two matchers to disambiguate between secrets with the same name across repositories: + +- **GH_RepoSecret** is matched by `name` + `repository_id` (the GitHub node_id of the repository). +- **GH_OrgSecret** is matched by `name` + `environmentid` (the node_id of the organization, which acts as the org-level secret scope). + +This means one `${{ secrets.MY_SECRET }}` expression in a workflow can produce up to two GH_UsesSecret edges — one to the repo-level secret and one to the org-level secret — reflecting that either could supply the value at runtime depending on scope precedence. + +### Context property + +The edge carries a `context` property indicating where the reference was found: +- `with` — inside a `with:` input block of a `uses:` action step +- `env` — inside the step's `env:` block +- `run` — inline within a `run:` shell script diff --git a/descriptions/edges/GH_UsesVariable.md b/descriptions/edges/GH_UsesVariable.md new file mode 100644 index 0000000..746553d --- /dev/null +++ b/descriptions/edges/GH_UsesVariable.md @@ -0,0 +1,19 @@ +## General Information + +The non-traversable GH_UsesVariable edge links a workflow step to the variable it references via a `${{ vars.NAME }}` expression. This edge maps variable consumption within workflows. Unlike secrets, variable values are readable via the API, making them lower sensitivity — but they can still influence workflow behavior (e.g., controlling target environments or feature flags). + +### Matching strategy + +Edges use `match_by: property` with two matchers to disambiguate between variables with the same name across repositories: + +- **GH_RepoVariable** is matched by `name` + `repository_id` (the GitHub node_id of the repository). +- **GH_OrgVariable** is matched by `name` + `environmentid` (the node_id of the organization, which acts as the org-level variable scope). + +This means one `${{ vars.MY_VAR }}` expression can produce up to two GH_UsesVariable edges — one to the repo-level variable and one to the org-level variable. + +### Context property + +The edge carries a `context` property indicating where the reference was found: +- `with` — inside a `with:` input block of a `uses:` action step +- `env` — inside the step's `env:` block +- `run` — inline within a `run:` shell script diff --git a/descriptions/edges/GH_ValidToken.md b/descriptions/edges/GH_ValidToken.md index 16340bf..9983c1f 100644 --- a/descriptions/edges/GH_ValidToken.md +++ b/descriptions/edges/GH_ValidToken.md @@ -1,3 +1,3 @@ ## General Information -The traversable `GH_ValidToken` edge represents a secret scanning alert that contains a valid, active GitHub Personal Access Token belonging to a specific user. Created by `Git-HoundSecretScanningAlert`, this edge is only emitted when the alert's state is `open`, the secret type is `github_personal_access_token`, and the token is confirmed valid by calling the GitHub API. This edge is traversable because possessing the leaked token grants the ability to act as the token's owner, effectively compromising that user's identity and all permissions granted to the token. +The traversable GH_ValidToken edge represents a secret scanning alert that contains a valid, active GitHub Personal Access Token belonging to a specific user. This edge is only emitted when the alert's state is `open`, the secret type is `github_personal_access_token`, and the token is confirmed valid by calling the GitHub API. This edge is traversable because possessing the leaked token grants the ability to act as the token's owner, effectively compromising that user's identity and all permissions granted to the token. diff --git a/descriptions/edges/GH_ViewDependabotAlerts.md b/descriptions/edges/GH_ViewDependabotAlerts.md index f7c3051..533c961 100644 --- a/descriptions/edges/GH_ViewDependabotAlerts.md +++ b/descriptions/edges/GH_ViewDependabotAlerts.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_ViewDependabotAlerts` edge represents a role's ability to view Dependabot security alerts, which reveal known vulnerabilities in the repository's dependencies. This permission is available to Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. This information could be used to identify and exploit unpatched vulnerabilities. +The non-traversable GH_ViewDependabotAlerts edge represents a role's ability to view Dependabot security alerts, which reveal known vulnerabilities in the repository's dependencies. This permission is available to Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. This information could be used to identify and exploit unpatched vulnerabilities. diff --git a/descriptions/edges/GH_ViewSecretScanningAlerts.md b/descriptions/edges/GH_ViewSecretScanningAlerts.md index 0b54721..4949b72 100644 --- a/descriptions/edges/GH_ViewSecretScanningAlerts.md +++ b/descriptions/edges/GH_ViewSecretScanningAlerts.md @@ -1,3 +1,3 @@ -# General Information +## General Information -The non-traversable `GH_ViewSecretScanningAlerts` edge represents that a role can view secret scanning alerts at the organization or repository level. This edge is dynamically generated from custom role permissions discovered by the collector. Secret scanning alerts may reveal details about leaked credentials, including partial or full secret values and the locations where they were detected. This makes the permission significant for security because an attacker with access to view these alerts could harvest exposed credentials for use in lateral movement or privilege escalation. +The non-traversable GH_ViewSecretScanningAlerts edge represents that a role can view secret scanning alerts at the organization or repository level. This edge is dynamically generated from custom role permissions discovered by the collector. Secret scanning alerts may reveal details about leaked credentials, including partial or full secret values and the locations where they were detected. This makes the permission significant for security because an attacker with access to view these alerts could harvest exposed credentials for use in lateral movement or privilege escalation. diff --git a/descriptions/edges/GH_WriteCodeScanning.md b/descriptions/edges/GH_WriteCodeScanning.md index 691ffad..42fbcbf 100644 --- a/descriptions/edges/GH_WriteCodeScanning.md +++ b/descriptions/edges/GH_WriteCodeScanning.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_WriteCodeScanning` edge represents a role's ability to upload code scanning analysis results. This permission is available to Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. An attacker could upload falsified SARIF results to suppress real alerts or inject misleading findings. +The non-traversable GH_WriteCodeScanning edge represents a role's ability to upload code scanning analysis results. This permission is available to Write, Maintain, and Admin roles and custom roles that have been granted this specific permission. An attacker could upload falsified SARIF results to suppress real alerts or inject misleading findings. diff --git a/descriptions/edges/GH_WriteOrganizationActionsSecrets.md b/descriptions/edges/GH_WriteOrganizationActionsSecrets.md index 45cd17f..e89dcc8 100644 --- a/descriptions/edges/GH_WriteOrganizationActionsSecrets.md +++ b/descriptions/edges/GH_WriteOrganizationActionsSecrets.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_WriteOrganizationActionsSecrets` edge represents that a role can write organization-level GitHub Actions secrets. This edge is dynamically generated from custom organization role permissions discovered by the collector. Organization-level secrets are available to workflows across multiple repositories and often contain credentials for external systems such as cloud providers, package registries, and deployment targets. An attacker with this permission could overwrite existing secrets to inject malicious credentials or create new secrets to facilitate lateral movement. +The non-traversable GH_WriteOrganizationActionsSecrets edge represents that a role can write organization-level GitHub Actions secrets. This edge is dynamically generated from custom organization role permissions discovered by the collector. Organization-level secrets are available to workflows across multiple repositories and often contain credentials for external systems such as cloud providers, package registries, and deployment targets. An attacker with this permission could overwrite existing secrets to inject malicious credentials or create new secrets to facilitate lateral movement. diff --git a/descriptions/edges/GH_WriteOrganizationActionsSettings.md b/descriptions/edges/GH_WriteOrganizationActionsSettings.md index 37e383b..1735a85 100644 --- a/descriptions/edges/GH_WriteOrganizationActionsSettings.md +++ b/descriptions/edges/GH_WriteOrganizationActionsSettings.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_WriteOrganizationActionsSettings` edge represents that a role can modify organization-level GitHub Actions settings. This edge is dynamically generated from custom organization role permissions discovered by the collector. These settings control which actions are allowed to run within the organization and the default permissions granted to the `GITHUB_TOKEN` in workflows. An attacker with this permission could weaken restrictions to allow untrusted third-party actions or elevate default token permissions to enable write access across repositories. +The non-traversable GH_WriteOrganizationActionsSettings edge represents that a role can modify organization-level GitHub Actions settings. This edge is dynamically generated from custom organization role permissions discovered by the collector. These settings control which actions are allowed to run within the organization and the default permissions granted to the `GITHUB_TOKEN` in workflows. An attacker with this permission could weaken restrictions to allow untrusted third-party actions or elevate default token permissions to enable write access across repositories. diff --git a/descriptions/edges/GH_WriteOrganizationActionsVariables.md b/descriptions/edges/GH_WriteOrganizationActionsVariables.md index 71e2ebd..bb88a27 100644 --- a/descriptions/edges/GH_WriteOrganizationActionsVariables.md +++ b/descriptions/edges/GH_WriteOrganizationActionsVariables.md @@ -1,3 +1,3 @@ -# General Information +## General Information -The non-traversable `GH_WriteOrganizationActionsVariables` edge represents that a role can write organization-level GitHub Actions variables. This edge is dynamically generated from custom organization role permissions discovered by the collector. Organization-level variables are available to workflows across multiple repositories and often contain configuration values such as environment URLs, feature flags, and service endpoints. An attacker with this permission could overwrite existing variables to redirect workflows to malicious endpoints or alter application behavior. +The non-traversable GH_WriteOrganizationActionsVariables edge represents that a role can write organization-level GitHub Actions variables. This edge is dynamically generated from custom organization role permissions discovered by the collector. Organization-level variables are available to workflows across multiple repositories and often contain configuration values such as environment URLs, feature flags, and service endpoints. An attacker with this permission could overwrite existing variables to redirect workflows to malicious endpoints or alter application behavior. diff --git a/descriptions/edges/GH_WriteOrganizationCustomOrgRole.md b/descriptions/edges/GH_WriteOrganizationCustomOrgRole.md index dee33b8..46c7887 100644 --- a/descriptions/edges/GH_WriteOrganizationCustomOrgRole.md +++ b/descriptions/edges/GH_WriteOrganizationCustomOrgRole.md @@ -1,3 +1,3 @@ ## General Information -The traversable `GH_WriteOrganizationCustomOrgRole` edge represents that a role can create or modify custom organization role definitions. This edge is dynamically generated from custom organization role permissions discovered by the collector. Modifying organization role definitions can escalate privileges because an attacker could add permissions to an existing custom role that is already assigned to their account, including setting the base_role to inherit all_repo_admin. Since this permission can only belong to custom organization roles, the user necessarily holds the role they can modify — guaranteeing a self-escalation path. This makes it a Tier Zero privilege escalation vector. +The traversable GH_WriteOrganizationCustomOrgRole edge represents that a role can create or modify custom organization role definitions. This edge is dynamically generated from custom organization role permissions discovered by the collector. Modifying organization role definitions can escalate privileges because an attacker could add permissions to an existing custom role that is already assigned to their account, including setting the base_role to inherit all_repo_admin. Since this permission can only belong to custom organization roles, the user necessarily holds the role they can modify — guaranteeing a self-escalation path. This makes it a Tier Zero privilege escalation vector. diff --git a/descriptions/edges/GH_WriteOrganizationCustomRepoRole.md b/descriptions/edges/GH_WriteOrganizationCustomRepoRole.md index 7eb9080..b58a3ee 100644 --- a/descriptions/edges/GH_WriteOrganizationCustomRepoRole.md +++ b/descriptions/edges/GH_WriteOrganizationCustomRepoRole.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_WriteOrganizationCustomRepoRole` edge represents that a role can create or modify custom repository role definitions. This edge is dynamically generated from custom organization role permissions discovered by the collector. Modifying repository role definitions can escalate privileges because an attacker could add permissions such as admin access, bypass branch protections, or secret management to a custom repo role that is already assigned to their account. This makes it a high-impact permission for gaining elevated access to repositories across the organization. +The non-traversable GH_WriteOrganizationCustomRepoRole edge represents that a role can create or modify custom repository role definitions. This edge is dynamically generated from custom organization role permissions discovered by the collector. Modifying repository role definitions can escalate privileges because an attacker could add permissions such as admin access, bypass branch protections, or secret management to a custom repo role that is already assigned to their account. This makes it a high-impact permission for gaining elevated access to repositories across the organization. diff --git a/descriptions/edges/GH_WriteOrganizationNetworkConfigurations.md b/descriptions/edges/GH_WriteOrganizationNetworkConfigurations.md index 1515128..6e48d96 100644 --- a/descriptions/edges/GH_WriteOrganizationNetworkConfigurations.md +++ b/descriptions/edges/GH_WriteOrganizationNetworkConfigurations.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_WriteOrganizationNetworkConfigurations` edge represents that a role can modify organization network configurations. This edge is dynamically generated from custom organization role permissions discovered by the collector. Network configurations control how GitHub-hosted runners connect to private resources such as internal APIs, databases, and cloud services. An attacker with this permission could modify network settings to route runner traffic through attacker-controlled infrastructure or grant runners access to previously isolated network segments. +The non-traversable GH_WriteOrganizationNetworkConfigurations edge represents that a role can modify organization network configurations. This edge is dynamically generated from custom organization role permissions discovered by the collector. Network configurations control how GitHub-hosted runners connect to private resources such as internal APIs, databases, and cloud services. An attacker with this permission could modify network settings to route runner traffic through attacker-controlled infrastructure or grant runners access to previously isolated network segments. diff --git a/descriptions/edges/GH_WriteRepoContents.md b/descriptions/edges/GH_WriteRepoContents.md index d34094b..fb8838a 100644 --- a/descriptions/edges/GH_WriteRepoContents.md +++ b/descriptions/edges/GH_WriteRepoContents.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_WriteRepoContents` edge represents a role's ability to push commits to the repository. This permission is available to Write, Maintain, and Admin roles. Pushing code can modify application behavior and introduce vulnerabilities, making this a security-significant edge. However, this edge represents only the raw permission; actual branch push capability is determined by the computed `GH_CanWriteBranch` edge, which factors in branch protection rules and push restrictions. +The non-traversable GH_WriteRepoContents edge represents a role's ability to push commits to the repository. This permission is available to Write, Maintain, and Admin roles. Pushing code can modify application behavior and introduce vulnerabilities, making this a security-significant edge. However, this edge represents only the raw permission; actual branch push capability is determined by the computed GH_CanWriteBranch edge, which factors in branch protection rules and push restrictions. diff --git a/descriptions/edges/GH_WriteRepoPullRequests.md b/descriptions/edges/GH_WriteRepoPullRequests.md index 9197c69..01aa5bb 100644 --- a/descriptions/edges/GH_WriteRepoPullRequests.md +++ b/descriptions/edges/GH_WriteRepoPullRequests.md @@ -1,3 +1,3 @@ ## General Information -The non-traversable `GH_WriteRepoPullRequests` edge represents a role's ability to create and merge pull requests in the repository. This permission is available to Write, Maintain, and Admin roles. Pull request merge access is security-significant because merging code into protected branches is a common vector for introducing unauthorized changes; however, actual merge capability on protected branches is further governed by branch protection rules and required reviews. +The non-traversable GH_WriteRepoPullRequests edge represents a role's ability to create and merge pull requests in the repository. This permission is available to Write, Maintain, and Admin roles. Pull request merge access is security-significant because merging code into protected branches is a common vector for introducing unauthorized changes; however, actual merge capability on protected branches is further governed by branch protection rules and required reviews. diff --git a/descriptions/nodes/GH_App.md b/descriptions/nodes/GH_App.md index 1446b48..5aabcbe 100644 --- a/descriptions/nodes/GH_App.md +++ b/descriptions/nodes/GH_App.md @@ -1,5 +1,5 @@ ## Description -Represents a GitHub App definition — the registered application entity. The app owner holds the private key that can generate installation access tokens for **every** `GH_AppInstallation` of this app. If the private key is compromised, all installations across all organizations are affected. +Represents a GitHub App definition — the registered application entity. The app owner holds the private key that can generate installation access tokens for **every** GH_AppInstallation of this app. If the private key is compromised, all installations across all organizations are affected. App definitions are retrieved via the public `GET /apps/{app_slug}` endpoint (no authentication required) after discovering unique app slugs from the organization's app installations. diff --git a/descriptions/nodes/GH_AppInstallation.md b/descriptions/nodes/GH_AppInstallation.md index 54f8113..cc6bd09 100644 --- a/descriptions/nodes/GH_AppInstallation.md +++ b/descriptions/nodes/GH_AppInstallation.md @@ -2,4 +2,4 @@ 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. -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). +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). diff --git a/descriptions/nodes/GH_Branch.md b/descriptions/nodes/GH_Branch.md index 92ab09e..6826226 100644 --- a/descriptions/nodes/GH_Branch.md +++ b/descriptions/nodes/GH_Branch.md @@ -1,3 +1,3 @@ ## Description -Represents a Git branch within a repository. Branch nodes capture basic branch information and whether the branch is protected. Protection rule details are stored in separate `GH_BranchProtectionRule` nodes, linked via `GH_ProtectedBy` edges. +Represents a Git branch within a repository. Branch nodes capture basic branch information and whether the branch is protected. Protection rule details are stored in separate GH_BranchProtectionRule nodes, linked via GH_ProtectedBy edges. diff --git a/descriptions/nodes/GH_BranchProtectionRule.md b/descriptions/nodes/GH_BranchProtectionRule.md index 96d9c5e..c4bde91 100644 --- a/descriptions/nodes/GH_BranchProtectionRule.md +++ b/descriptions/nodes/GH_BranchProtectionRule.md @@ -9,26 +9,26 @@ A single protection rule can apply to multiple branches via pattern matching (e. Branch protection rules are critical security controls. Key settings to review: - **enforce_admins**: Enforces merge-gate controls (PR reviews, lock branch) for admins and users with `bypass_branch_protection`. Does **not** enforce push-gate controls (`push_restrictions`) for admins or users with `push_protected_branch`. -- **required_pull_request_reviews**: Blocks direct pushes to existing protected branches. Bypassed by `GH_BypassBranchProtection` and `GH_BypassPullRequestAllowances` (both suppressed by `enforce_admins`). -- **push_restrictions**: Restricts who can push. Bypassed by `GH_PushProtectedBranch`, `GH_AdminTo`, and `GH_RestrictionsCanPush` (none suppressed by `enforce_admins`). +- **required_pull_request_reviews**: Blocks direct pushes to existing protected branches. Bypassed by GH_BypassBranchProtection and GH_BypassPullRequestAllowances (both suppressed by `enforce_admins`). +- **push_restrictions**: Restricts who can push. Bypassed by GH_PushProtectedBranch, GH_AdminTo, and GH_RestrictionsCanPush (none suppressed by `enforce_admins`). - **blocks_creations**: Restricts new branch creation when `push_restrictions` is also `true`. Same bypass vectors as `push_restrictions`. Silently reverts to `false` if `push_restrictions` is disabled. -- **lock_branch**: Makes branch read-only. Bypassed by `GH_BypassBranchProtection` (suppressed by `enforce_admins`). +- **lock_branch**: Makes branch read-only. Bypassed by GH_BypassBranchProtection (suppressed by `enforce_admins`). - **require_code_owner_reviews**: If `false`, changes to critical paths may not require owner approval. - **allows_force_pushes**: Controls whether history rewrites are allowed. Does **not** grant push access — it is not a bypass mechanism. - **allows_deletions**: If `true`, branches can be deleted (potentially losing code). ### Secret Exfiltration Mitigation -The only branch protection configuration that blocks the write-access → workflow → secrets exfiltration attack path is `push_restrictions` + `blocks_creations` on a `*` pattern rule. However, users with `GH_PushProtectedBranch`, `GH_AdminTo`, `GH_RestrictionsCanPush`, or `GH_EditRepoProtections` can bypass this control. +The only branch protection configuration that blocks the write-access → workflow → secrets exfiltration attack path is `push_restrictions` + `blocks_creations` on a `*` pattern rule. However, users with GH_PushProtectedBranch, GH_AdminTo, GH_RestrictionsCanPush, or GH_EditRepoProtections can bypass this control. -For complete analysis, see [MITIGATING_CONTROLS.md](../MITIGATING_CONTROLS.md). +For complete analysis, see [BloodHound Docs: GitHub - Mitigating Controls](https://bloodhound.specterops.io/opengraph/extensions/github/mitigating-controls). ### Identifying Bypass Actors Use these edges to identify users and teams with elevated branch permissions: -- `GH_BypassPullRequestAllowances` — can bypass PR requirements on a specific rule (PR reviews only) -- `GH_RestrictionsCanPush` — can push despite push restrictions on a specific rule -- `GH_BypassBranchProtection` — repo-wide bypass of merge-gate controls (PR reviews + lock branch) -- `GH_PushProtectedBranch` — repo-wide bypass of push-gate controls (push restrictions + blocks creations) -- `GH_EditRepoProtections` — can remove/modify protection rules entirely +- GH_BypassPullRequestAllowances — can bypass PR requirements on a specific rule (PR reviews only) +- GH_RestrictionsCanPush — can push despite push restrictions on a specific rule +- GH_BypassBranchProtection — repo-wide bypass of merge-gate controls (PR reviews + lock branch) +- GH_PushProtectedBranch — repo-wide bypass of push-gate controls (push restrictions + blocks creations) +- GH_EditRepoProtections — can remove/modify protection rules entirely diff --git a/descriptions/nodes/GH_RepoRole.md b/descriptions/nodes/GH_RepoRole.md index 945f129..108c57d 100644 --- a/descriptions/nodes/GH_RepoRole.md +++ b/descriptions/nodes/GH_RepoRole.md @@ -1,3 +1,3 @@ ## Description -Represents a repository-level permission role. Each repository has five default roles (Read, Write, Admin, Triage, Maintain) plus any custom repository roles defined at the organization level. Repo roles define what actions a user or team can perform on a specific repository. Default roles form an inheritance hierarchy (Triage → Read, Maintain → Write, Admin includes all), and custom roles inherit from one of the base roles. +Represents a repository-level permission role. Each repository has five default roles (Read, Write, Admin, Triage, Maintain) plus any custom repository roles defined at the organization level. Repo roles define what actions a user or team can perform on a specific repository. Default roles form an inheritance hierarchy (Triage -> Read, Maintain -> Write, Admin includes all), and custom roles inherit from one of the base roles. diff --git a/descriptions/nodes/GH_WorkflowJob.md b/descriptions/nodes/GH_WorkflowJob.md new file mode 100644 index 0000000..b375adf --- /dev/null +++ b/descriptions/nodes/GH_WorkflowJob.md @@ -0,0 +1,3 @@ +## Description + +Represents a single job within a GitHub Actions workflow. Jobs are the top-level execution units of a workflow — they run on a runner, hold a set of steps, and can declare permissions, environments, and dependencies on other jobs. diff --git a/descriptions/nodes/GH_WorkflowStep.md b/descriptions/nodes/GH_WorkflowStep.md new file mode 100644 index 0000000..fac90e4 --- /dev/null +++ b/descriptions/nodes/GH_WorkflowStep.md @@ -0,0 +1,3 @@ +## Description + +Represents a single step within a GitHub Actions job. A step is either a `uses:` action reference or a `run:` shell command. Steps are the leaf nodes of the workflow execution tree and are the primary location where secrets and variables are consumed. diff --git a/docs/og-docs-automation b/docs/og-docs-automation new file mode 160000 index 0000000..400bd30 --- /dev/null +++ b/docs/og-docs-automation @@ -0,0 +1 @@ +Subproject commit 400bd3010e6b106b77991ad6eb2eb586cb627862 diff --git a/docs/og-docs.json b/docs/og-docs.json new file mode 100644 index 0000000..59a9d65 --- /dev/null +++ b/docs/og-docs.json @@ -0,0 +1,14 @@ +{ + "extensionSchemaPath": "extension/schema.json", + "extensionShortName": "GitHub", + "gitHubBaseUrl": "https://github.com/SpecterOps/openhound-github", + "stripTitlePrefix": "GitHub: ", + "savedSearchesDir": "extension/saved_searches", + "zoneRulesDir": "extension/privilege_zone_rules", + "nodeDescriptionsDir": "descriptions/nodes", + "edgeDescriptionsDir": "descriptions/edges", + "openHoundStructure": true, + "imagesDir": "descriptions/images", + "iconSize": 32, + "iconScale": 0.55 +} diff --git a/extension/privilege_zone_rules/t0-all-repo-admin-role.json b/extension/privilege_zone_rules/t0-all-repo-admin-role.json index bbf5314..eff2bed 100644 --- a/extension/privilege_zone_rules/t0-all-repo-admin-role.json +++ b/extension/privilege_zone_rules/t0-all-repo-admin-role.json @@ -1,7 +1,7 @@ { "name": "GitHub: Tier Zero All-Repo Admin Role", "description": "The synthetic all_repo_admin role grants admin access to every repository in the organization. This role is inherited by the owners role via GH_HasBaseRole and cascades admin permissions including branch protection editing, secret access, and deploy key management to all repositories.", - "cypher": "MATCH (n:GH_OrgRole) WHERE n.name ENDS WITH '/all_repo_admin' RETURN n", + "cypher": "MATCH (n:GH_OrgRole)\nWHERE n.name ENDS\nWITH '/all_repo_admin'\nRETURN n", "enabled": true, "zone": "Tier Zero", "allow_disable": true diff --git a/extension/privilege_zone_rules/t0-app-installations-all-repos.json b/extension/privilege_zone_rules/t0-app-installations-all-repos.json index 3fcf3f8..0ef7811 100644 --- a/extension/privilege_zone_rules/t0-app-installations-all-repos.json +++ b/extension/privilege_zone_rules/t0-app-installations-all-repos.json @@ -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'}) WHERE n.permissions CONTAINS '\"write\"' RETURN n", + "cypher": "MATCH (n:GH_AppInstallation {repository_selection:'all'})\nWHERE n.permissions CONTAINS '\"write\"'\nRETURN n", "enabled": true, "zone": "Tier Zero", "allow_disable": true diff --git a/extension/privilege_zone_rules/t0-apps-all-repos.json b/extension/privilege_zone_rules/t0-apps-all-repos.json index aec4744..040e7e8 100644 --- a/extension/privilege_zone_rules/t0-apps-all-repos.json +++ b/extension/privilege_zone_rules/t0-apps-all-repos.json @@ -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'}) WHERE i.permissions CONTAINS '\"write\"' RETURN n", + "cypher": "MATCH (n:GH_App)-[:GH_InstalledAs]->(i:GH_AppInstallation {repository_selection:'all'})\nWHERE i.permissions CONTAINS '\"write\"'\nRETURN n", "enabled": true, "zone": "Tier Zero", "allow_disable": true diff --git a/extension/privilege_zone_rules/t0-external-identities-owners.json b/extension/privilege_zone_rules/t0-external-identities-owners.json index 261f275..7b95fec 100644 --- a/extension/privilege_zone_rules/t0-external-identities-owners.json +++ b/extension/privilege_zone_rules/t0-external-identities-owners.json @@ -1,7 +1,7 @@ { "name": "GitHub: Tier Zero External Identities (Owner-Mapped)", "description": "External identities from SAML/SCIM providers that map to GitHub users holding the owners role. Compromise of these external identities in the identity provider grants organizational owner access to GitHub via SSO.", - "cypher": "MATCH (n:GH_ExternalIdentity)-[:GH_MapsToUser]->(:GH_User)-[:GH_HasRole]->(:GH_OrgRole {short_name:'owners'}) RETURN n", + "cypher": "MATCH (n:GH_ExternalIdentity)-[:GH_MapsToUser]->(:GH_User)-[:GH_HasRole]->(:GH_OrgRole {short_name:'owners'})\nRETURN n", "enabled": true, "zone": "Tier Zero", "allow_disable": true diff --git a/extension/privilege_zone_rules/t0-organizations.json b/extension/privilege_zone_rules/t0-organizations.json index 4fa6d83..e0335b4 100644 --- a/extension/privilege_zone_rules/t0-organizations.json +++ b/extension/privilege_zone_rules/t0-organizations.json @@ -1,7 +1,7 @@ { "name": "GitHub: Tier Zero Organizations", "description": "GitHub organizations are the root trust boundary for all repositories, teams, users, and settings. Compromise of the organization grants full administrative control over all contained assets.", - "cypher": "MATCH (n:GH_Organization) RETURN n", + "cypher": "MATCH (n:GH_Organization)\nRETURN n", "enabled": true, "zone": "Tier Zero", "allow_disable": true diff --git a/extension/privilege_zone_rules/t0-owner-users.json b/extension/privilege_zone_rules/t0-owner-users.json index ffcb1e5..2bd2834 100644 --- a/extension/privilege_zone_rules/t0-owner-users.json +++ b/extension/privilege_zone_rules/t0-owner-users.json @@ -1,7 +1,7 @@ { "name": "GitHub: Tier Zero Owner Users", "description": "Users who hold the organization owners role have full administrative control over the GitHub organization. Compromise of any owner account grants control over all repositories, secrets, SSO configuration, and cloud identities.", - "cypher": "MATCH (n:GH_User)-[:GH_HasRole]->(:GH_OrgRole {short_name:'owners'}) RETURN n", + "cypher": "MATCH (n:GH_User)-[:GH_HasRole]->(:GH_OrgRole {short_name:'owners'})\nRETURN n", "enabled": true, "zone": "Tier Zero", "allow_disable": true diff --git a/extension/privilege_zone_rules/t0-owners-role.json b/extension/privilege_zone_rules/t0-owners-role.json index 9efcd39..972da2f 100644 --- a/extension/privilege_zone_rules/t0-owners-role.json +++ b/extension/privilege_zone_rules/t0-owners-role.json @@ -1,7 +1,7 @@ { "name": "GitHub: Tier Zero Owners Role", "description": "The owners organization role grants full administrative control including all repository admin, member management, SSO configuration, app management, and billing. Owners inherit all_repo_admin, cascading admin access to every repository, secret, environment, and cloud identity in the organization.", - "cypher": "MATCH (n:GH_OrgRole {short_name:'owners'}) RETURN n", + "cypher": "MATCH (n:GH_OrgRole {short_name:'owners'})\nRETURN n", "enabled": true, "zone": "Tier Zero", "allow_disable": true diff --git a/extension/privilege_zone_rules/t0-pats-all-repos.json b/extension/privilege_zone_rules/t0-pats-all-repos.json index 63e85d2..7b3deca 100644 --- a/extension/privilege_zone_rules/t0-pats-all-repos.json +++ b/extension/privilege_zone_rules/t0-pats-all-repos.json @@ -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'}) WHERE n.permissions CONTAINS '\"write\"' RETURN n", + "cypher": "MATCH (n:GH_PersonalAccessToken {repository_selection:'all'})\nWHERE n.permissions CONTAINS '\"write\"'\nRETURN n", "enabled": true, "zone": "Tier Zero", "allow_disable": true diff --git a/extension/privilege_zone_rules/t0-privilege-escalation-roles.json b/extension/privilege_zone_rules/t0-privilege-escalation-roles.json index a29fa1c..2ec1095 100644 --- a/extension/privilege_zone_rules/t0-privilege-escalation-roles.json +++ b/extension/privilege_zone_rules/t0-privilege-escalation-roles.json @@ -1,7 +1,7 @@ { "name": "GitHub: Tier Zero Privilege Escalation Roles", "description": "Custom organization roles with write_organization_custom_org_role permission can modify organization role definitions, including setting the base_role to inherit all_repo_admin. Since this permission only exists on custom organization roles, the holder can escalate the role they already hold — a guaranteed self-escalation path to full organizational control.", - "cypher": "MATCH (n:GH_OrgRole)-[:GH_WriteOrganizationCustomOrgRole]->(:GH_Organization) RETURN n", + "cypher": "MATCH (n:GH_OrgRole)-[:GH_WriteOrganizationCustomOrgRole]->(:GH_Organization)\nRETURN n", "enabled": true, "zone": "Tier Zero", "allow_disable": true diff --git a/extension/privilege_zone_rules/t0-privilege-escalation-users.json b/extension/privilege_zone_rules/t0-privilege-escalation-users.json index 6292a6e..a98cffe 100644 --- a/extension/privilege_zone_rules/t0-privilege-escalation-users.json +++ b/extension/privilege_zone_rules/t0-privilege-escalation-users.json @@ -1,7 +1,7 @@ { "name": "GitHub: Tier Zero Privilege Escalation Users", "description": "Users who hold custom organization roles with write_organization_custom_org_role permission. These users can modify organization role definitions — including the role they hold — to set the base_role to all_repo_admin, granting themselves admin access to every repository in the organization.", - "cypher": "MATCH (n:GH_User)-[:GH_HasRole|GH_HasBaseRole*1..]->(:GH_OrgRole)-[:GH_WriteOrganizationCustomOrgRole]->(:GH_Organization) RETURN n", + "cypher": "MATCH (n:GH_User)-[:GH_HasRole|GH_HasBaseRole*1..]->(:GH_OrgRole)-[:GH_WriteOrganizationCustomOrgRole]->(:GH_Organization)\nRETURN n", "enabled": true, "zone": "Tier Zero", "allow_disable": true diff --git a/extension/privilege_zone_rules/t0-saml-identity-providers.json b/extension/privilege_zone_rules/t0-saml-identity-providers.json index 61160f1..bacd75c 100644 --- a/extension/privilege_zone_rules/t0-saml-identity-providers.json +++ b/extension/privilege_zone_rules/t0-saml-identity-providers.json @@ -1,7 +1,7 @@ { "name": "GitHub: Tier Zero SAML Identity Providers", "description": "SAML identity providers control authentication for all organization members via SSO. Compromise of the identity provider grants the ability to impersonate any user, including organization owners, by manipulating SAML assertions or resetting credentials.", - "cypher": "MATCH (n:GH_SamlIdentityProvider) RETURN n", + "cypher": "MATCH (n:GH_SamlIdentityProvider)\nRETURN n", "enabled": true, "zone": "Tier Zero", "allow_disable": true diff --git a/extension/saved_searches/README.md b/extension/saved_searches/README.md index 9a4450d..f7416b6 100644 --- a/extension/saved_searches/README.md +++ b/extension/saved_searches/README.md @@ -1,4 +1,4 @@ -# GitHound Saved Queries +# Saved Queries Pre-built Cypher queries for identifying security-relevant configurations across your GitHub organization. Each query is stored as an individual JSON file with `name`, `query`, and `description` fields, designed to be imported into BloodHound's saved queries feature. diff --git a/extension/saved_searches/actions-sha-pinning-not-required.json b/extension/saved_searches/actions-sha-pinning-not-required.json index abfe080..bffd975 100644 --- a/extension/saved_searches/actions-sha-pinning-not-required.json +++ b/extension/saved_searches/actions-sha-pinning-not-required.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Actions SHA Pinning Not Required", - "query": "MATCH (org:GH_Organization {actions_sha_pinning_required: false}) RETURN org LIMIT 1000", + "name": "GitHub: Actions SHA Pinning Not Required", + "query": "MATCH (org:GH_Organization {actions_sha_pinning_required: false})\nRETURN org\nLIMIT 1000", "description": "Finds organizations that do not require SHA pinning for GitHub Actions. Without pinning, actions referenced by tag can be silently replaced with malicious versions." } diff --git a/extension/saved_searches/active-leaked-secrets.json b/extension/saved_searches/active-leaked-secrets.json index 1083cc8..9198c61 100644 --- a/extension/saved_searches/active-leaked-secrets.json +++ b/extension/saved_searches/active-leaked-secrets.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Active Leaked Secrets", - "query": "MATCH p=(:GH_Repository)-[:GH_Contains]->(alert:GH_SecretScanningAlert {state: 'open', validity: 'active'}) RETURN p LIMIT 1000", + "name": "GitHub: Active Leaked Secrets", + "query": "MATCH p=(:GH_Repository)-[:GH_Contains]->(alert:GH_SecretScanningAlert {state: 'open', validity: 'active'})\nRETURN p\nLIMIT 1000", "description": "Finds secret scanning alerts that are both unresolved and confirmed active. These are valid, usable credentials committed to source code and represent an immediate compromise risk." } diff --git a/extension/saved_searches/advanced-security-disabled-new-repos.json b/extension/saved_searches/advanced-security-disabled-new-repos.json index 9c98a6c..868c7ab 100644 --- a/extension/saved_searches/advanced-security-disabled-new-repos.json +++ b/extension/saved_searches/advanced-security-disabled-new-repos.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Advanced Security Disabled for New Repositories", - "query": "MATCH (org:GH_Organization {advanced_security_enabled_for_new_repositories: false}) RETURN org LIMIT 1000", + "name": "GitHub: Advanced Security Disabled for New Repositories", + "query": "MATCH (org:GH_Organization {advanced_security_enabled_for_new_repositories: false})\nRETURN org\nLIMIT 1000", "description": "Finds organizations where GitHub Advanced Security is not automatically enabled for new repositories. New repositories will lack code scanning, secret scanning, and other GHAS features." } diff --git a/extension/saved_searches/all-actions-allowed.json b/extension/saved_searches/all-actions-allowed.json index b680912..d0d5117 100644 --- a/extension/saved_searches/all-actions-allowed.json +++ b/extension/saved_searches/all-actions-allowed.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] All GitHub Actions Allowed", - "query": "MATCH (org:GH_Organization {actions_allowed_actions: 'all'}) RETURN org LIMIT 1000", + "name": "GitHub: All GitHub Actions Allowed", + "query": "MATCH (org:GH_Organization {actions_allowed_actions: 'all'})\nRETURN org\nLIMIT 1000", "description": "Finds organizations that allow all GitHub Actions to run, including third-party actions from the marketplace. This creates supply chain risk if a malicious or compromised action is used." } diff --git a/extension/saved_searches/app-installations-all-repos.json b/extension/saved_searches/app-installations-all-repos.json index 2c51fdc..b1a21f2 100644 --- a/extension/saved_searches/app-installations-all-repos.json +++ b/extension/saved_searches/app-installations-all-repos.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] App Installations with Access to All Repositories", - "query": "MATCH (app:GH_AppInstallation {repository_selection: 'all'}) RETURN app LIMIT 1000", + "name": "GitHub: App Installations with Access to All Repositories", + "query": "MATCH (app:GH_AppInstallation {repository_selection: 'all'})\nRETURN app\nLIMIT 1000", "description": "Finds GitHub App installations that have access to every repository in the organization. A compromised app credential would affect all repositories." } diff --git a/extension/saved_searches/branch-protection-admins-not-enforced.json b/extension/saved_searches/branch-protection-admins-not-enforced.json index 0cbd07c..9f1a8a8 100644 --- a/extension/saved_searches/branch-protection-admins-not-enforced.json +++ b/extension/saved_searches/branch-protection-admins-not-enforced.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Branch Protection Rules - Admins Not Enforced", - "query": "MATCH p=(:GH_BranchProtectionRule {enforce_admins: false})-[:GH_ProtectedBy]->(:GH_Branch) RETURN p LIMIT 1000", + "name": "GitHub: Branch Protection Rules - Admins Not Enforced", + "query": "MATCH p=(:GH_BranchProtectionRule {enforce_admins: false})-[:GH_ProtectedBy]->(:GH_Branch)\nRETURN p\nLIMIT 1000", "description": "Finds branch protection rules where administrators can bypass all protections. Admins can push directly, skip reviews, and override status checks on these branches." } diff --git a/extension/saved_searches/branch-protection-deletions-allowed.json b/extension/saved_searches/branch-protection-deletions-allowed.json index b11181e..2e036c1 100644 --- a/extension/saved_searches/branch-protection-deletions-allowed.json +++ b/extension/saved_searches/branch-protection-deletions-allowed.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Branch Protection Rules - Deletions Allowed", - "query": "MATCH p=(:GH_BranchProtectionRule {allows_deletions: true})-[:GH_ProtectedBy]->(:GH_Branch) RETURN p LIMIT 1000", + "name": "GitHub: Branch Protection Rules - Deletions Allowed", + "query": "MATCH p=(:GH_BranchProtectionRule {allows_deletions: true})-[:GH_ProtectedBy]->(:GH_Branch)\nRETURN p\nLIMIT 1000", "description": "Finds protected branches that can be deleted. Branch deletion can result in loss of code and removal of audit history." } diff --git a/extension/saved_searches/branch-protection-force-pushes.json b/extension/saved_searches/branch-protection-force-pushes.json index 461bfeb..fec33b7 100644 --- a/extension/saved_searches/branch-protection-force-pushes.json +++ b/extension/saved_searches/branch-protection-force-pushes.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Branch Protection Rules - Force Pushes Allowed", - "query": "MATCH p=(:GH_BranchProtectionRule {allows_force_pushes: true})-[:GH_ProtectedBy]->(:GH_Branch) RETURN p LIMIT 1000", + "name": "GitHub: Branch Protection Rules - Force Pushes Allowed", + "query": "MATCH p=(:GH_BranchProtectionRule {allows_force_pushes: true})-[:GH_ProtectedBy]->(:GH_Branch)\nRETURN p\nLIMIT 1000", "description": "Finds branches where force pushes are allowed. Force pushes can rewrite commit history, potentially hiding malicious changes or destroying audit trails." } diff --git a/extension/saved_searches/branch-protection-no-code-owner-reviews.json b/extension/saved_searches/branch-protection-no-code-owner-reviews.json index 2c02969..8d270ff 100644 --- a/extension/saved_searches/branch-protection-no-code-owner-reviews.json +++ b/extension/saved_searches/branch-protection-no-code-owner-reviews.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Branch Protection Rules - No Code Owner Reviews", - "query": "MATCH p=(:GH_BranchProtectionRule {require_code_owner_reviews: false})-[:GH_ProtectedBy]->(:GH_Branch) RETURN p LIMIT 1000", + "name": "GitHub: Branch Protection Rules - No Code Owner Reviews", + "query": "MATCH p=(:GH_BranchProtectionRule {require_code_owner_reviews: false})-[:GH_ProtectedBy]->(:GH_Branch)\nRETURN p\nLIMIT 1000", "description": "Finds branches where code owner reviews are not required. Changes to security-critical paths can be merged without authorization from the designated code owners." } diff --git a/extension/saved_searches/branch-protection-no-pr-reviews.json b/extension/saved_searches/branch-protection-no-pr-reviews.json index 430edc8..21250d9 100644 --- a/extension/saved_searches/branch-protection-no-pr-reviews.json +++ b/extension/saved_searches/branch-protection-no-pr-reviews.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Branch Protection Rules - No Pull Request Reviews Required", - "query": "MATCH p=(:GH_BranchProtectionRule {required_pull_request_reviews: false})-[:GH_ProtectedBy]->(:GH_Branch) RETURN p LIMIT 1000", + "name": "GitHub: Branch Protection Rules - No Pull Request Reviews Required", + "query": "MATCH p=(:GH_BranchProtectionRule {required_pull_request_reviews: false})-[:GH_ProtectedBy]->(:GH_Branch)\nRETURN p\nLIMIT 1000", "description": "Finds branches where pull request reviews are not required. Code can be merged directly without peer review, increasing the risk of undetected vulnerabilities or malicious changes." } diff --git a/extension/saved_searches/branch-protection-no-status-checks.json b/extension/saved_searches/branch-protection-no-status-checks.json index ea5ae42..68e639a 100644 --- a/extension/saved_searches/branch-protection-no-status-checks.json +++ b/extension/saved_searches/branch-protection-no-status-checks.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Branch Protection Rules - No Status Checks Required", - "query": "MATCH p=(:GH_BranchProtectionRule {requires_status_checks: false})-[:GH_ProtectedBy]->(:GH_Branch) RETURN p LIMIT 1000", + "name": "GitHub: Branch Protection Rules - No Status Checks Required", + "query": "MATCH p=(:GH_BranchProtectionRule {requires_status_checks: false})-[:GH_ProtectedBy]->(:GH_Branch)\nRETURN p\nLIMIT 1000", "description": "Finds branches where CI/CD status checks are not required before merging. Code with failing tests or security scans can be merged into protected branches." } diff --git a/extension/saved_searches/branch-protection-self-approval.json b/extension/saved_searches/branch-protection-self-approval.json index f30c85a..53870bf 100644 --- a/extension/saved_searches/branch-protection-self-approval.json +++ b/extension/saved_searches/branch-protection-self-approval.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Branch Protection Rules - Self-Approval Allowed", - "query": "MATCH p=(:GH_BranchProtectionRule {require_last_push_approval: false})-[:GH_ProtectedBy]->(:GH_Branch) RETURN p LIMIT 1000", + "name": "GitHub: Branch Protection Rules - Self-Approval Allowed", + "query": "MATCH p=(:GH_BranchProtectionRule {require_last_push_approval: false})-[:GH_ProtectedBy]->(:GH_Branch)\nRETURN p\nLIMIT 1000", "description": "Finds branches where the author of the last push can approve their own pull request. This allows a single person to both write and approve code changes." } diff --git a/extension/saved_searches/branch-protection-stale-reviews.json b/extension/saved_searches/branch-protection-stale-reviews.json index cb00960..87f56eb 100644 --- a/extension/saved_searches/branch-protection-stale-reviews.json +++ b/extension/saved_searches/branch-protection-stale-reviews.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Branch Protection Rules - Stale Reviews Not Dismissed", - "query": "MATCH p=(:GH_BranchProtectionRule {dismisses_stale_reviews: false})-[:GH_ProtectedBy]->(:GH_Branch) RETURN p LIMIT 1000", + "name": "GitHub: Branch Protection Rules - Stale Reviews Not Dismissed", + "query": "MATCH p=(:GH_BranchProtectionRule {dismisses_stale_reviews: false})-[:GH_ProtectedBy]->(:GH_Branch)\nRETURN p\nLIMIT 1000", "description": "Finds branches where stale reviews are not dismissed when new commits are pushed. An attacker could get a review approved, then push additional malicious commits that inherit the stale approval." } diff --git a/extension/saved_searches/bypass-pr-requirements.json b/extension/saved_searches/bypass-pr-requirements.json index f98796d..9ab14b9 100644 --- a/extension/saved_searches/bypass-pr-requirements.json +++ b/extension/saved_searches/bypass-pr-requirements.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Users Who Can Bypass Pull Request Requirements", - "query": "MATCH p=(actor)-[:GH_BypassPullRequestAllowances]->(rule:GH_BranchProtectionRule)-[:GH_ProtectedBy]->(branch:GH_Branch) RETURN p LIMIT 1000", + "name": "GitHub: Users Who Can Bypass Pull Request Requirements", + "query": "MATCH p=(actor)-[:GH_BypassPullRequestAllowances]->(rule:GH_BranchProtectionRule)-[:GH_ProtectedBy]->(branch:GH_Branch)\nRETURN p\nLIMIT 1000", "description": "Finds users and teams that can bypass pull request review requirements on protected branches. These actors can merge code without any reviews." } diff --git a/extension/saved_searches/dangerous-branch-perms.json b/extension/saved_searches/dangerous-branch-perms.json index c82bc4f..72313be 100644 --- a/extension/saved_searches/dangerous-branch-perms.json +++ b/extension/saved_searches/dangerous-branch-perms.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Dangerous Branch Permissions", - "query": "MATCH p=(:GH_User)-[:GH_HasRole|GH_HasBaseRole|GH_MemberOf*1..]->(:GH_RepoRole)-[:GH_PushProtectedBranch|GH_BypassBranchProtection]-(r:GH_Repository) MATCH p1=(:GH_User)-[:GH_BypassPullRequestAllowances|GH_RestrictionsCanPush]->(rule:GH_BranchProtectionRule)-[:GH_ProtectedBy]->(b:GH_Branch) RETURN p,p1 LIMIT 1000", + "name": "GitHub: Dangerous Branch Permissions", + "query": "MATCH p=(:GH_User)-[:GH_HasRole|GH_HasBaseRole|GH_MemberOf*1..]->(:GH_RepoRole)-[:GH_PushProtectedBranch|GH_BypassBranchProtection]-(r:GH_Repository)\nMATCH p1=(:GH_User)-[:GH_BypassPullRequestAllowances|GH_RestrictionsCanPush]->(rule:GH_BranchProtectionRule)-[:GH_ProtectedBy]->(b:GH_Branch)\nRETURN p,p1\nLIMIT 1000", "description": "Identifies users with dangerous branch permissions in a GitHub organization, including bypass allowances on protection rules." } diff --git a/extension/saved_searches/default-repository-permissions.json b/extension/saved_searches/default-repository-permissions.json index 31de342..5c943d6 100644 --- a/extension/saved_searches/default-repository-permissions.json +++ b/extension/saved_searches/default-repository-permissions.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Organizations with default repository permission", - "query": "MATCH (o:GH_Organization) WHERE o.default_repository_permission <> 'none' RETURN o LIMIT 1000", + "name": "GitHub: Organizations with default repository permission", + "query": "MATCH (o:GH_Organization)\nWHERE o.default_repository_permission <> 'none'\nRETURN o\nLIMIT 1000", "description": "Returns organizations that have a default repository permission other than 'none'." } diff --git a/extension/saved_searches/demo-sso-to-cloud-round-trip.json b/extension/saved_searches/demo-sso-to-cloud-round-trip.json index fecbdb1..85e43d8 100644 --- a/extension/saved_searches/demo-sso-to-cloud-round-trip.json +++ b/extension/saved_searches/demo-sso-to-cloud-round-trip.json @@ -1,5 +1,5 @@ { - "name": "[Demo] SSO Round-Trip: Azure/Okta → GitHub → Cloud Identity", - "query": "MATCH p1=(extUser)-[:SyncedToGHUser]->(ghUser:GH_User) MATCH p2=(ghUser)-[:GH_HasRole|GH_HasBaseRole|GH_MemberOf*1..]->(:GH_RepoRole)-[:GH_WriteRepoContents]->(:GH_Repository)-[:GH_CanAssumeIdentity]->(cred:AZFederatedIdentityCredential) RETURN p1, p2 LIMIT 1000", + "name": "[Demo] SSO Round-Trip: Azure/Okta \u2192 GitHub \u2192 Cloud Identity", + "query": "MATCH p1=(extUser)-[:SyncedToGHUser]->(ghUser:GH_User)\nMATCH p2=(ghUser)-[:GH_HasRole|GH_HasBaseRole|GH_MemberOf*1..]->(:GH_RepoRole)-[:GH_WriteRepoContents]->(:GH_Repository)-[:GH_CanAssumeIdentity]->(cred:AZFederatedIdentityCredential)\nRETURN p1, p2\nLIMIT 1000", "description": "The cloud-to-cloud pivot through GitHub: a compromised Azure or Okta identity syncs to a GitHub user via SSO. That GitHub user has write access to repositories configured with OIDC federation to Azure workload identities. The attacker pivots from one cloud identity through GitHub into a completely different Azure identity — crossing cloud boundaries twice in a single attack chain." } diff --git a/extension/saved_searches/dependabot-alerts-disabled-new-repos.json b/extension/saved_searches/dependabot-alerts-disabled-new-repos.json index aea3a6d..c71c8c2 100644 --- a/extension/saved_searches/dependabot-alerts-disabled-new-repos.json +++ b/extension/saved_searches/dependabot-alerts-disabled-new-repos.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Dependabot Alerts Disabled for New Repositories", - "query": "MATCH (org:GH_Organization {dependabot_alerts_enabled_for_new_repositories: false}) RETURN org LIMIT 1000", + "name": "GitHub: Dependabot Alerts Disabled for New Repositories", + "query": "MATCH (org:GH_Organization {dependabot_alerts_enabled_for_new_repositories: false})\nRETURN org\nLIMIT 1000", "description": "Finds organizations where Dependabot alerts are not enabled for new repositories. Vulnerable dependencies in new repositories will go undetected." } diff --git a/extension/saved_searches/dependabot-updates-disabled-new-repos.json b/extension/saved_searches/dependabot-updates-disabled-new-repos.json index c216811..bfbc704 100644 --- a/extension/saved_searches/dependabot-updates-disabled-new-repos.json +++ b/extension/saved_searches/dependabot-updates-disabled-new-repos.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Dependabot Security Updates Disabled for New Repositories", - "query": "MATCH (org:GH_Organization {dependabot_security_updates_enabled_for_new_repositories: false}) RETURN org LIMIT 1000", + "name": "GitHub: Dependabot Security Updates Disabled for New Repositories", + "query": "MATCH (org:GH_Organization {dependabot_security_updates_enabled_for_new_repositories: false})\nRETURN org\nLIMIT 1000", "description": "Finds organizations where Dependabot security update PRs are not enabled for new repositories. Known vulnerable dependencies will not receive automated fix PRs." } diff --git a/extension/saved_searches/dependency-graph-disabled-new-repos.json b/extension/saved_searches/dependency-graph-disabled-new-repos.json index ec6d916..0b72d5a 100644 --- a/extension/saved_searches/dependency-graph-disabled-new-repos.json +++ b/extension/saved_searches/dependency-graph-disabled-new-repos.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Dependency Graph Disabled for New Repositories", - "query": "MATCH (org:GH_Organization {dependency_graph_enabled_for_new_repositories: false}) RETURN org LIMIT 1000", + "name": "GitHub: Dependency Graph Disabled for New Repositories", + "query": "MATCH (org:GH_Organization {dependency_graph_enabled_for_new_repositories: false})\nRETURN org\nLIMIT 1000", "description": "Finds organizations where the dependency graph is not enabled for new repositories. Without the dependency graph, transitive dependency vulnerabilities cannot be tracked." } diff --git a/extension/saved_searches/environments-admin-bypass.json b/extension/saved_searches/environments-admin-bypass.json index c8b8100..08447e4 100644 --- a/extension/saved_searches/environments-admin-bypass.json +++ b/extension/saved_searches/environments-admin-bypass.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Environments Where Admins Can Bypass Protections", - "query": "MATCH p=(:GH_Repository)-[:GH_HasEnvironment]->(env:GH_Environment {can_admins_bypass: true}) RETURN p LIMIT 1000", + "name": "GitHub: Environments Where Admins Can Bypass Protections", + "query": "MATCH p=(:GH_Repository)-[:GH_HasEnvironment]->(env:GH_Environment {can_admins_bypass: true})\nRETURN p\nLIMIT 1000", "description": "Finds deployment environments where administrators can bypass protection rules such as required reviewers and wait timers. Admins can deploy to these environments without any approval." } diff --git a/extension/saved_searches/expired-pats.json b/extension/saved_searches/expired-pats.json index d32312f..e849144 100644 --- a/extension/saved_searches/expired-pats.json +++ b/extension/saved_searches/expired-pats.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Expired Personal Access Tokens", - "query": "MATCH p=(:GH_User)-[:GH_HasPersonalAccessToken]->(token:GH_PersonalAccessToken {token_expired: true}) RETURN p LIMIT 1000", + "name": "GitHub: Expired Personal Access Tokens", + "query": "MATCH p=(:GH_User)-[:GH_HasPersonalAccessToken]->(token:GH_PersonalAccessToken {token_expired: true})\nRETURN p\nLIMIT 1000", "description": "Finds expired personal access tokens that still exist. Expired tokens should be cleaned up to reduce credential inventory and audit noise." } diff --git a/extension/saved_searches/external-identities-without-scim.json b/extension/saved_searches/external-identities-without-scim.json index 78c46d2..805b85f 100644 --- a/extension/saved_searches/external-identities-without-scim.json +++ b/extension/saved_searches/external-identities-without-scim.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] External Identities Without SCIM Provisioning", - "query": "MATCH (ei:GH_ExternalIdentity) WHERE ei.scim_identity_username = '' RETURN ei LIMIT 1000", + "name": "GitHub: External Identities Without SCIM Provisioning", + "query": "MATCH (ei:GH_ExternalIdentity)\nWHERE ei.scim_identity_username = ''\nRETURN ei\nLIMIT 1000", "description": "Finds external identities that lack SCIM synchronization. Without SCIM, user deprovisioning in the identity provider will not automatically revoke GitHub access." } diff --git a/extension/saved_searches/github-to-azure-identity.json b/extension/saved_searches/github-to-azure-identity.json index 51d2e47..f1e6c2e 100644 --- a/extension/saved_searches/github-to-azure-identity.json +++ b/extension/saved_searches/github-to-azure-identity.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] GitHub-to-Azure Identity Assumptions", - "query": "MATCH p=(src)-[:GH_CanAssumeIdentity]->(cred:AZFederatedIdentityCredential) RETURN p LIMIT 1000", + "name": "GitHub: GitHub-to-Azure Identity Assumptions", + "query": "MATCH p=(src)-[:GH_CanAssumeIdentity]->(cred:AZFederatedIdentityCredential)\nRETURN p\nLIMIT 1000", "description": "Finds GitHub entities (repositories, branches, environments) that can assume Azure identities via OIDC federation. Verify that each trust relationship is intentional and scoped appropriately." } diff --git a/extension/saved_searches/global-repo-perms.json b/extension/saved_searches/global-repo-perms.json index 4fd5e53..4eda589 100644 --- a/extension/saved_searches/global-repo-perms.json +++ b/extension/saved_searches/global-repo-perms.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Global Repo Permissions", - "query": "MATCH p=(:GH_User)-[:GH_HasBaseRole|GH_HasRole|GH_MemberOf*1..3]->(role:GH_OrgRole) WHERE role.short_name CONTAINS 'all_repo_' RETURN p LIMIT 1000", + "name": "GitHub: Global Repo Permissions", + "query": "MATCH p=(:GH_User)-[:GH_HasBaseRole|GH_HasRole|GH_MemberOf*1..3]->(role:GH_OrgRole)\nWHERE role.short_name CONTAINS 'all_repo_'\nRETURN p\nLIMIT 1000", "description": "Returns all users who hold a global repository permission role (i.e., roles that are not default)." } diff --git a/extension/saved_searches/hybrid-identities.json b/extension/saved_searches/hybrid-identities.json index 55aabfa..756adc9 100644 --- a/extension/saved_searches/hybrid-identities.json +++ b/extension/saved_searches/hybrid-identities.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] External Identities", - "query": "MATCH p=(s)-[]->(d:GH_User) WHERE s:AZUser OR s:OktaUser RETURN p LIMIT 1000", + "name": "GitHub: External Identities", + "query": "MATCH p=(s)-[]->(d:GH_User)\nWHERE s:AZUser\nOR s:Okta_User\nRETURN p\nLIMIT 1000", "description": "Returns all external identities (e.g., Azure or Okta users) that are associated with GitHub users." } diff --git a/extension/saved_searches/members-can-change-repo-visibility.json b/extension/saved_searches/members-can-change-repo-visibility.json index d0d9247..9e2289a 100644 --- a/extension/saved_searches/members-can-change-repo-visibility.json +++ b/extension/saved_searches/members-can-change-repo-visibility.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Members Can Change Repository Visibility", - "query": "MATCH (org:GH_Organization {members_can_change_repo_visibility: true}) RETURN org LIMIT 1000", + "name": "GitHub: Members Can Change Repository Visibility", + "query": "MATCH (org:GH_Organization {members_can_change_repo_visibility: true})\nRETURN org\nLIMIT 1000", "description": "Finds organizations where members can change repository visibility. This allows any member to make a private repository public, potentially exposing source code and secrets." } diff --git a/extension/saved_searches/members-can-create-pages.json b/extension/saved_searches/members-can-create-pages.json index a8b3fcd..2ddad3a 100644 --- a/extension/saved_searches/members-can-create-pages.json +++ b/extension/saved_searches/members-can-create-pages.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Members Can Create GitHub Pages", - "query": "MATCH (org:GH_Organization {members_can_create_pages: true}) RETURN org LIMIT 1000", + "name": "GitHub: Members Can Create GitHub Pages", + "query": "MATCH (org:GH_Organization {members_can_create_pages: true})\nRETURN org\nLIMIT 1000", "description": "Finds organizations where members can create GitHub Pages sites. Pages can be used to host phishing content, data exfiltration endpoints, or other malicious resources." } diff --git a/extension/saved_searches/members-can-create-public-repos.json b/extension/saved_searches/members-can-create-public-repos.json index 8999da0..0161941 100644 --- a/extension/saved_searches/members-can-create-public-repos.json +++ b/extension/saved_searches/members-can-create-public-repos.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Members Can Create Public Repositories", - "query": "MATCH (org:GH_Organization {members_can_create_public_repositories: true}) RETURN org LIMIT 1000", + "name": "GitHub: Members Can Create Public Repositories", + "query": "MATCH (org:GH_Organization {members_can_create_public_repositories: true})\nRETURN org\nLIMIT 1000", "description": "Finds organizations where members can create internet-facing public repositories. This increases the risk of accidental exposure of proprietary code or secrets." } diff --git a/extension/saved_searches/members-can-delete-repos.json b/extension/saved_searches/members-can-delete-repos.json index 03a293b..a5dde56 100644 --- a/extension/saved_searches/members-can-delete-repos.json +++ b/extension/saved_searches/members-can-delete-repos.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Members Can Delete Repositories", - "query": "MATCH (org:GH_Organization {members_can_delete_repositories: true}) RETURN org LIMIT 1000", + "name": "GitHub: Members Can Delete Repositories", + "query": "MATCH (org:GH_Organization {members_can_delete_repositories: true})\nRETURN org\nLIMIT 1000", "description": "Finds organizations where members can delete repositories. This poses a risk of accidental or malicious destruction of code and audit history." } diff --git a/extension/saved_searches/members-can-fork-private-repos.json b/extension/saved_searches/members-can-fork-private-repos.json index 9a74216..a05d24b 100644 --- a/extension/saved_searches/members-can-fork-private-repos.json +++ b/extension/saved_searches/members-can-fork-private-repos.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Members Can Fork Private Repositories", - "query": "MATCH (org:GH_Organization {members_can_fork_private_repositories: true}) RETURN org LIMIT 1000", + "name": "GitHub: Members Can Fork Private Repositories", + "query": "MATCH (org:GH_Organization {members_can_fork_private_repositories: true})\nRETURN org\nLIMIT 1000", "description": "Finds organizations where members can fork private repositories to personal accounts. Forked copies leave organizational control and oversight." } diff --git a/extension/saved_searches/members-can-invite-outside-collaborators.json b/extension/saved_searches/members-can-invite-outside-collaborators.json index 6cd7b53..c722138 100644 --- a/extension/saved_searches/members-can-invite-outside-collaborators.json +++ b/extension/saved_searches/members-can-invite-outside-collaborators.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Members Can Invite Outside Collaborators", - "query": "MATCH (org:GH_Organization {members_can_invite_outside_collaborators: true}) RETURN org LIMIT 1000", + "name": "GitHub: Members Can Invite Outside Collaborators", + "query": "MATCH (org:GH_Organization {members_can_invite_outside_collaborators: true})\nRETURN org\nLIMIT 1000", "description": "Finds organizations where any member can invite external users. This can lead to unauthorized third-party access to repositories without centralized oversight." } diff --git a/extension/saved_searches/org-owners.json b/extension/saved_searches/org-owners.json index 939420b..1ea106d 100644 --- a/extension/saved_searches/org-owners.json +++ b/extension/saved_searches/org-owners.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Organization Owners", - "query": "MATCH p=(:GH_User)-[:GH_HasRole]->(:GH_OrgRole {short_name:'owners'}) RETURN p LIMIT 1000", - "description": "Returns all users hold the organization owners role." + "name": "GitHub: Organization Owners", + "query": "MATCH p=(:GH_User)-[:GH_HasRole]->(:GH_OrgRole {short_name:'owners'})\nRETURN p\nLIMIT 1000", + "description": "Returns all users who hold the organization owners role." } diff --git a/extension/saved_searches/orgs-without-2fa.json b/extension/saved_searches/orgs-without-2fa.json index 5bd5378..d305de7 100644 --- a/extension/saved_searches/orgs-without-2fa.json +++ b/extension/saved_searches/orgs-without-2fa.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Organizations without 2FA", - "query": "MATCH (o:GH_Organization) WHERE o.two_factor_requirement_enabled = false RETURN o LIMIT 1000", + "name": "GitHub: Organizations without 2FA", + "query": "MATCH (o:GH_Organization)\nWHERE o.two_factor_requirement_enabled = false\nRETURN o\nLIMIT 1000", "description": "Returns organizations that do not require two-factor authentication." } diff --git a/extension/saved_searches/pats-all-repo-access.json b/extension/saved_searches/pats-all-repo-access.json index 640a7b0..ad65049 100644 --- a/extension/saved_searches/pats-all-repo-access.json +++ b/extension/saved_searches/pats-all-repo-access.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] PATs with Access to All Repositories", - "query": "MATCH p=(:GH_User)-[:GH_HasPersonalAccessToken]->(token:GH_PersonalAccessToken {repository_selection: 'all'}) RETURN p LIMIT 1000", + "name": "GitHub: PATs with Access to All Repositories", + "query": "MATCH p=(:GH_User)-[:GH_HasPersonalAccessToken]->(token:GH_PersonalAccessToken {repository_selection: 'all'})\nRETURN p\nLIMIT 1000", "description": "Finds fine-grained personal access tokens scoped to all repositories. A single compromised token grants access to every repository in the organization." } diff --git a/extension/saved_searches/pending-pat-requests.json b/extension/saved_searches/pending-pat-requests.json index 994c52d..4c60b2b 100644 --- a/extension/saved_searches/pending-pat-requests.json +++ b/extension/saved_searches/pending-pat-requests.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Pending PAT Requests", - "query": "MATCH p=(:GH_User)-[:GH_HasPersonalAccessTokenRequest]->(req:GH_PersonalAccessTokenRequest) RETURN p LIMIT 1000", + "name": "GitHub: Pending PAT Requests", + "query": "MATCH p=(:GH_User)-[:GH_HasPersonalAccessTokenRequest]->(req:GH_PersonalAccessTokenRequest)\nRETURN p\nLIMIT 1000", "description": "Finds pending fine-grained personal access token requests awaiting approval. Review these to ensure requested permissions are appropriate before granting access." } diff --git a/extension/saved_searches/private-repos-forking-allowed.json b/extension/saved_searches/private-repos-forking-allowed.json index e5c6d0b..2c75fbb 100644 --- a/extension/saved_searches/private-repos-forking-allowed.json +++ b/extension/saved_searches/private-repos-forking-allowed.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Private Repositories with Forking Allowed", - "query": "MATCH (repo:GH_Repository {visibility: 'private', allow_forking: true}) RETURN repo LIMIT 1000", + "name": "GitHub: Private Repositories with Forking Allowed", + "query": "MATCH (repo:GH_Repository {visibility: 'private', allow_forking: true})\nRETURN repo\nLIMIT 1000", "description": "Finds private repositories that allow forking. Forked copies of private repositories can leave organizational governance and visibility." } diff --git a/extension/saved_searches/privileged-custom-org-roles.json b/extension/saved_searches/privileged-custom-org-roles.json index 56e9522..367a9bd 100644 --- a/extension/saved_searches/privileged-custom-org-roles.json +++ b/extension/saved_searches/privileged-custom-org-roles.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Privileged Custom Org Roles", - "query": "MATCH p=(role:GH_OrgRole {type:'custom'})-[r]->(dest) WHERE dest:GH_Organization OR dest:GH_OrgRole RETURN p LIMIT 1000", + "name": "GitHub: Privileged Custom Org Roles", + "query": "MATCH p=(role:GH_OrgRole {type:'custom'})-[r]->(dest)\nWHERE dest:GH_Organization\nOR dest:GH_OrgRole\nRETURN p\nLIMIT 1000", "description": "Returns all custom organization roles that are privileged (i.e., have permissions that are not default)" } diff --git a/extension/saved_searches/privileged-hybrid-identities.json b/extension/saved_searches/privileged-hybrid-identities.json index 04a27e5..daff24a 100644 --- a/extension/saved_searches/privileged-hybrid-identities.json +++ b/extension/saved_searches/privileged-hybrid-identities.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Privileged Hybrid Identities", - "query": "MATCH p=()-[:GH_SyncedTo]->(:GH_User)-[:GH_HasRole]->(:GH_OrgRole {short_name:'owners'}) RETURN p LIMIT 1000", + "name": "GitHub: Privileged Hybrid Identities", + "query": "MATCH p=()-[:GH_SyncedTo]->(:GH_User)-[:GH_HasRole]->(:GH_OrgRole {short_name:'owners'})\nRETURN p\nLIMIT 1000", "description": "Returns all hybrid identities (e.g., Azure or Okta users) that are associated with GitHub users who hold the organization owners role." } diff --git a/extension/saved_searches/public-repos.json b/extension/saved_searches/public-repos.json index 27ce306..4ea897b 100644 --- a/extension/saved_searches/public-repos.json +++ b/extension/saved_searches/public-repos.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Public Repositories", - "query": "MATCH (repo:GH_Repository {private: false}) RETURN repo LIMIT 1000", + "name": "GitHub: Public Repositories", + "query": "MATCH (repo:GH_Repository {private: false})\nRETURN repo\nLIMIT 1000", "description": "Returns all public repositories." } diff --git a/extension/saved_searches/push-protection-disabled-new-repos.json b/extension/saved_searches/push-protection-disabled-new-repos.json index 6d3b680..269fa14 100644 --- a/extension/saved_searches/push-protection-disabled-new-repos.json +++ b/extension/saved_searches/push-protection-disabled-new-repos.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Secret Scanning Push Protection Disabled for New Repositories", - "query": "MATCH (org:GH_Organization {secret_scanning_push_protection_enabled_for_new_repositories: false}) RETURN org LIMIT 1000", + "name": "GitHub: Secret Scanning Push Protection Disabled for New Repositories", + "query": "MATCH (org:GH_Organization {secret_scanning_push_protection_enabled_for_new_repositories: false})\nRETURN org\nLIMIT 1000", "description": "Finds organizations where push protection is not enabled for new repositories. Without push protection, secrets can be committed without being blocked before they reach the repository." } diff --git a/extension/saved_searches/push-to-protected-branches.json b/extension/saved_searches/push-to-protected-branches.json index 349617b..dc147e0 100644 --- a/extension/saved_searches/push-to-protected-branches.json +++ b/extension/saved_searches/push-to-protected-branches.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Users Who Can Push to Protected Branches", - "query": "MATCH p=(actor)-[:GH_RestrictionsCanPush]->(rule:GH_BranchProtectionRule)-[:GH_ProtectedBy]->(branch:GH_Branch) RETURN p LIMIT 1000", + "name": "GitHub: Users Who Can Push to Protected Branches", + "query": "MATCH p=(actor)-[:GH_RestrictionsCanPush]->(rule:GH_BranchProtectionRule)-[:GH_ProtectedBy]->(branch:GH_Branch)\nRETURN p\nLIMIT 1000", "description": "Finds users and teams that are allowed to push directly to protected branches when push restrictions are enabled. These actors bypass the normal pull request workflow." } diff --git a/extension/saved_searches/repos-secret-scanning-disabled.json b/extension/saved_searches/repos-secret-scanning-disabled.json index d0ed64b..c4becc5 100644 --- a/extension/saved_searches/repos-secret-scanning-disabled.json +++ b/extension/saved_searches/repos-secret-scanning-disabled.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Repositories with Secret Scanning Disabled", - "query": "MATCH (repo:GH_Repository {secret_scanning: 'disabled'}) RETURN repo LIMIT 1000", + "name": "GitHub: Repositories with Secret Scanning Disabled", + "query": "MATCH (repo:GH_Repository {secret_scanning: 'disabled'})\nRETURN repo\nLIMIT 1000", "description": "Finds repositories where secret scanning is disabled. Committed credentials in these repositories will not be detected by GitHub." } diff --git a/extension/saved_searches/repos-vulnerable-to-workflow-secret-exfil.json b/extension/saved_searches/repos-vulnerable-to-workflow-secret-exfil.json index 525672e..55f0a4e 100644 --- a/extension/saved_searches/repos-vulnerable-to-workflow-secret-exfil.json +++ b/extension/saved_searches/repos-vulnerable-to-workflow-secret-exfil.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Repos Vulnerable to Workflow Secret Exfiltration", - "query": "MATCH p1=(:GH_User)-[:GH_HasRole|GH_HasBaseRole|GH_MemberOf*1..]->(:GH_RepoRole)-[:GH_CanCreateBranch]->(repo:GH_Repository)-[:GH_HasSecret]->(s) WHERE (s:GH_RepoSecret OR s:GH_OrgSecret) OPTIONAL MATCH p2=(repo)<-[:GH_CanCreateBranch]-(:GH_User) OPTIONAL MATCH p3=(repo)<-[:GH_CanCreateBranch]-(:GH_Team)<-[:GH_HasRole|GH_MemberOf|GH_AddMember*1..]-(:GH_User) RETURN p1, p2, p3 LIMIT 1000", - "description": "Secrets reachable by users who can create new branches (computed by Compute-GitHoundBranchAccess). The GH_CanCreateBranch edge accounts for branch protection rules, push restrictions, blocks_creations settings, and all bypass mechanisms (admin, push_protected_branch, pushAllowances). Edges emit from RepoRole in the common case; per-actor edges from User/Team are only present when per-rule allowances grant additional access beyond the role." + "name": "GitHub: Repos Vulnerable to Workflow Secret Exfiltration", + "query": "MATCH p1=(:GH_User)-[:GH_HasRole|GH_HasBaseRole|GH_MemberOf*1..]->(:GH_RepoRole)-[:GH_CanCreateBranch]->(repo:GH_Repository)-[:GH_HasSecret]->(s)\nWHERE (s:GH_RepoSecret\nOR s:GH_OrgSecret)\nOPTIONAL MATCH p2=(repo)<-[:GH_CanCreateBranch]-(:GH_User)\nOPTIONAL MATCH p3=(repo)<-[:GH_CanCreateBranch]-(:GH_Team)<-[:GH_HasRole|GH_MemberOf|GH_AddMember*1..]-(:GH_User)\nRETURN p1, p2, p3\nLIMIT 1000", + "description": "Secrets reachable by users who can create new branches. The GH_CanCreateBranch edge accounts for branch protection rules, push restrictions, blocks_creations settings, and all bypass mechanisms (admin, push_protected_branch, pushAllowances). Edges emit from RepoRole in the common case; per-actor edges from User/Team are only present when per-rule allowances grant additional access beyond the role." } diff --git a/extension/saved_searches/repository-workflows.json b/extension/saved_searches/repository-workflows.json index 6a421f7..bcaed4f 100644 --- a/extension/saved_searches/repository-workflows.json +++ b/extension/saved_searches/repository-workflows.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Repository Workflows", - "query": "MATCH p=(:GH_Repository)-[:GH_HasWorkflow]->(:GH_Workflow) RETURN p LIMIT 1000", + "name": "GitHub: Repository Workflows", + "query": "MATCH p=(:GH_Repository)-[:GH_HasWorkflow]->(:GH_Workflow)\nRETURN p\nLIMIT 1000", "description": "Returns all repository workflows" } diff --git a/extension/saved_searches/saml-configuration.json b/extension/saved_searches/saml-configuration.json index a1b532a..33a0f1c 100644 --- a/extension/saved_searches/saml-configuration.json +++ b/extension/saved_searches/saml-configuration.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] SAML Configuration Mapping", - "query": "MATCH p=(OIP:GH_SamlIdentityProvider)-[:GH_HasExternalIdentity]->(EI:GH_ExternalIdentity) MATCH p1=(OIP)<-[:GH_HasSamlIdentityProvider]-(:GH_Organization) MATCH p2=(EI)-[:GH_MapsToUser]->() RETURN p,p1,p2 LIMIT 1000", + "name": "GitHub: SAML Configuration Mapping", + "query": "MATCH p=(OIP:GH_SamlIdentityProvider)-[:GH_HasExternalIdentity]->(EI:GH_ExternalIdentity)\nMATCH p1=(OIP)<-[:GH_HasSamlIdentityProvider]-(:GH_Organization)\nMATCH p2=(EI)-[:GH_MapsToUser]->()\nRETURN p,p1,p2\nLIMIT 1000", "description": "Finds SAML Identity Providers, their external identities, and mapped users." } diff --git a/extension/saved_searches/secret-scanning-alerts.json b/extension/saved_searches/secret-scanning-alerts.json index 64b608d..4cb0801 100644 --- a/extension/saved_searches/secret-scanning-alerts.json +++ b/extension/saved_searches/secret-scanning-alerts.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Secret Scanning Alerts", - "query": "MATCH p=(repo:GH_Repository)-[:GH_Contains]->(:GH_SecretScanningAlert {state:'open'}) RETURN p LIMIT 1000", + "name": "GitHub: Secret Scanning Alerts", + "query": "MATCH p=(repo:GH_Repository)-[:GH_Contains]->(:GH_SecretScanningAlert {state:'open'})\nRETURN p\nLIMIT 1000", "description": "Returns all repositories that have secret scanning alerts." } diff --git a/extension/saved_searches/secret-scanning-disabled-new-repos.json b/extension/saved_searches/secret-scanning-disabled-new-repos.json index ffd1bf9..42ca05a 100644 --- a/extension/saved_searches/secret-scanning-disabled-new-repos.json +++ b/extension/saved_searches/secret-scanning-disabled-new-repos.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Secret Scanning Disabled for New Repositories", - "query": "MATCH (org:GH_Organization {secret_scanning_enabled_for_new_repositories: false}) RETURN org LIMIT 1000", + "name": "GitHub: Secret Scanning Disabled for New Repositories", + "query": "MATCH (org:GH_Organization {secret_scanning_enabled_for_new_repositories: false})\nRETURN org\nLIMIT 1000", "description": "Finds organizations where secret scanning is not automatically enabled for new repositories. New repositories will not detect committed credentials until manually enabled." } diff --git a/extension/saved_searches/secrets-reachable-by-user.json b/extension/saved_searches/secrets-reachable-by-user.json index 9a5264d..77004e5 100644 --- a/extension/saved_searches/secrets-reachable-by-user.json +++ b/extension/saved_searches/secrets-reachable-by-user.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Secrets Reachable by User", - "query": "MATCH p=(:GH_User)-[:GH_HasRole|GH_HasBaseRole|GH_MemberOf*1..]->(:GH_RepoRole)-[:GH_WriteRepoContents]->(:GH_Repository)-[:GH_HasSecret]->(s) WHERE s:GH_RepoSecret OR s:GH_OrgSecret RETURN p LIMIT 1000", + "name": "GitHub: Secrets Reachable by User", + "query": "MATCH p=(:GH_User)-[:GH_HasRole|GH_HasBaseRole|GH_MemberOf*1..]->(:GH_RepoRole)-[:GH_WriteRepoContents]->(:GH_Repository)-[:GH_HasSecret]->(s)\nWHERE s:GH_RepoSecret\nOR s:GH_OrgSecret\nRETURN p\nLIMIT 1000", "description": "Returns all repo and org secrets reachable by users through write access. Users with write access can create GitHub Actions workflows to access secrets." } diff --git a/extension/saved_searches/team-membership-admin.json b/extension/saved_searches/team-membership-admin.json index 49e5dab..35614ad 100644 --- a/extension/saved_searches/team-membership-admin.json +++ b/extension/saved_searches/team-membership-admin.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Team Membership Admins", - "query": "MATCH p=(:GH_User)-[:GH_HasRole]->(:GH_TeamRole)-[:GH_AddMember]->(team:GH_Team) MATCH p1=(team)<-[:GH_MemberOf]-(:GH_Team)<-[:GH_AddMember]-(:GH_TeamRole)<-[:GH_HasRole]-(:GH_User) RETURN p,p1 LIMIT 1000", + "name": "GitHub: Team Membership Admins", + "query": "MATCH p=(:GH_User)-[:GH_HasRole]->(:GH_TeamRole)-[:GH_AddMember]->(team:GH_Team)\nMATCH p1=(team)<-[:GH_MemberOf]-(:GH_Team)<-[:GH_AddMember]-(:GH_TeamRole)<-[:GH_HasRole]-(:GH_User)\nRETURN p,p1\nLIMIT 1000", "description": "Returns all users who hold the maintainer role over a team, this also represents team nesting." } diff --git a/extension/saved_searches/team-structure.json b/extension/saved_searches/team-structure.json index 89dea37..25c592e 100644 --- a/extension/saved_searches/team-structure.json +++ b/extension/saved_searches/team-structure.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Team Structure", - "query": "MATCH p=(:GH_User)-[:GH_HasRole]->(:GH_TeamRole)-[:GH_MemberOf*1..]->(:GH_Team) RETURN p LIMIT 1000", + "name": "GitHub: Team Structure", + "query": "MATCH p=(:GH_User)-[:GH_HasRole]->(:GH_TeamRole)-[:GH_MemberOf*1..]->(:GH_Team)\nRETURN p\nLIMIT 1000", "description": "Returns the structure of teams within organizations, including team roles and their members." } diff --git a/extension/saved_searches/unprotected-branches.json b/extension/saved_searches/unprotected-branches.json index d6e8353..b5ace62 100644 --- a/extension/saved_searches/unprotected-branches.json +++ b/extension/saved_searches/unprotected-branches.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Unprotected Branches", - "query": "MATCH p=(repo:GH_Repository)-[:GH_HasBranch]-(:GH_Branch {protected: false}) RETURN p LIMIT 1000", + "name": "GitHub: Unprotected Branches", + "query": "MATCH p=(repo:GH_Repository)-[:GH_HasBranch]-(:GH_Branch {protected: false})\nRETURN p\nLIMIT 1000", "description": "Returns all unprotected branches in repositories." } diff --git a/extension/saved_searches/unprotected-default-branch-with-workflow.json b/extension/saved_searches/unprotected-default-branch-with-workflow.json index 5d1ced0..70de2fb 100644 --- a/extension/saved_searches/unprotected-default-branch-with-workflow.json +++ b/extension/saved_searches/unprotected-default-branch-with-workflow.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Repositories with Workflows and Unprotected Default Branch", - "query": "MATCH p=(repo:GH_Repository)-[:GH_HasWorkflow]->(:GH_Workflow) MATCH p1=(repo)-[:GH_HasBranch]->(branch:GH_Branch) WHERE repo.default_branch = branch.short_name RETURN p1 LIMIT 1000", + "name": "GitHub: Repositories with Workflows and Unprotected Default Branch", + "query": "MATCH p=(repo:GH_Repository)-[:GH_HasWorkflow]->(:GH_Workflow)\nMATCH p1=(repo)-[:GH_HasBranch]->(branch:GH_Branch)\nWHERE repo.default_branch = branch.short_name\nAND branch.protected = false\nRETURN p1\nLIMIT 1000", "description": "Returns all repositories that have GitHub Actions workflows and an unprotected default branch. This means that users with GH_WriteRepoContents to the Repository can overwrite or change the workflow." } diff --git a/extension/saved_searches/unprotected-default-branches.json b/extension/saved_searches/unprotected-default-branches.json index e13ef2f..b9add1b 100644 --- a/extension/saved_searches/unprotected-default-branches.json +++ b/extension/saved_searches/unprotected-default-branches.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Unprotected Default Branches", - "query": "MATCH p=(repo:GH_Repository)-[:GH_HasBranch]-(branch:GH_Branch {protected: false}) WHERE repo.default_branch = branch.short_name RETURN p LIMIT 1000", + "name": "GitHub: Unprotected Default Branches", + "query": "MATCH p=(repo:GH_Repository)-[:GH_HasBranch]-(branch:GH_Branch {protected: false})\nWHERE repo.default_branch = branch.short_name\nRETURN p\nLIMIT 1000", "description": "Returns all default branches in repositories that are not protected." } diff --git a/extension/saved_searches/web-commit-signoff-not-required.json b/extension/saved_searches/web-commit-signoff-not-required.json index cf65620..896d383 100644 --- a/extension/saved_searches/web-commit-signoff-not-required.json +++ b/extension/saved_searches/web-commit-signoff-not-required.json @@ -1,5 +1,5 @@ { - "name": "[GitHub] Web Commit Signoff Not Required", - "query": "MATCH (org:GH_Organization {web_commit_signoff_required: false}) RETURN org LIMIT 1000", + "name": "GitHub: Web Commit Signoff Not Required", + "query": "MATCH (org:GH_Organization {web_commit_signoff_required: false})\nRETURN org\nLIMIT 1000", "description": "Finds organizations that do not require sign-off for web-based commits. Without signoff, commit attribution cannot be verified." } diff --git a/extension/schema.json b/extension/schema.json index 3eb8e32..b0d2b87 100644 --- a/extension/schema.json +++ b/extension/schema.json @@ -2,7 +2,7 @@ "schema": { "name": "SOGitHub", "display_name": "GitHub Extension (by SpecterOps)", - "version": "v1.2.1", + "version": "v1.2.2", "namespace": "GH" }, "node_kinds": [ @@ -778,12 +778,12 @@ }, { "name": "GH_UsesSecret", - "description": "[Workflow] Step references a secret by name — GH_WorkflowStep → GH_Secret (name match)", + "description": "[Workflow] Step references a secret by name — GH_WorkflowStep → GH_RepoSecret / GH_OrgSecret (name match)", "is_traversable": false }, { "name": "GH_UsesVariable", - "description": "[Workflow] Step references a variable by name — GH_WorkflowStep → GH_Variable (name match)", + "description": "[Workflow] Step references a variable by name — GH_WorkflowStep → GH_RepoVariable / GH_OrgVariable (name match)", "is_traversable": false } ],