Skip to main content
Applies to BloodHound Enterprise and CE The following custom Cypher queries can be imported into BloodHound to enhance visibility. Each query is defined in a JSON file located in the Queries directory of the GitHound repository.
This file is automatically generated from the JSON query files that are bundled with the GitHound collector.

Actions SHA Pinning Not Required

Finds organizations that do not require SHA pinning for GitHub Actions. Without pinning, actions referenced by tag can be silently replaced with malicious versions.
MATCH (org:GH_Organization {actions_sha_pinning_required: false})
RETURN org
LIMIT 1000
This query can be imported into BloodHound from the actions-sha-pinning-not-required.json file.

Active Leaked Secrets

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.
MATCH p=(:GH_Repository)-[:GH_Contains]->(alert:GH_SecretScanningAlert {state: 'open', validity: 'active'})
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the active-leaked-secrets.json file.

Advanced Security Disabled for New Repositories

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.
MATCH (org:GH_Organization {advanced_security_enabled_for_new_repositories: false})
RETURN org
LIMIT 1000
This query can be imported into BloodHound from the advanced-security-disabled-new-repos.json file.

All GitHub Actions Allowed

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.
MATCH (org:GH_Organization {actions_allowed_actions: 'all'})
RETURN org
LIMIT 1000
This query can be imported into BloodHound from the all-actions-allowed.json file.

App Installations with Access to All Repositories

Finds GitHub App installations that have access to every repository in the organization. A compromised app credential would affect all repositories.
MATCH (app:GH_AppInstallation {repository_selection: 'all'})
RETURN app
LIMIT 1000
This query can be imported into BloodHound from the app-installations-all-repos.json file.

Branch Protection Rules - Admins Not Enforced

Finds branch protection rules where administrators can bypass all protections. Admins can push directly, skip reviews, and override status checks on these branches.
MATCH p=(:GH_BranchProtectionRule {enforce_admins: false})-[:GH_ProtectedBy]->(:GH_Branch)
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the branch-protection-admins-not-enforced.json file.

Branch Protection Rules - Deletions Allowed

Finds protected branches that can be deleted. Branch deletion can result in loss of code and removal of audit history.
MATCH p=(:GH_BranchProtectionRule {allows_deletions: true})-[:GH_ProtectedBy]->(:GH_Branch)
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the branch-protection-deletions-allowed.json file.

Branch Protection Rules - Force Pushes Allowed

Finds branches where force pushes are allowed. Force pushes can rewrite commit history, potentially hiding malicious changes or destroying audit trails.
MATCH p=(:GH_BranchProtectionRule {allows_force_pushes: true})-[:GH_ProtectedBy]->(:GH_Branch)
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the branch-protection-force-pushes.json file.

Branch Protection Rules - No Code Owner Reviews

Finds branches where code owner reviews are not required. Changes to security-critical paths can be merged without authorization from the designated code owners.
MATCH p=(:GH_BranchProtectionRule {require_code_owner_reviews: false})-[:GH_ProtectedBy]->(:GH_Branch)
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the branch-protection-no-code-owner-reviews.json file.

Branch Protection Rules - No Pull Request Reviews Required

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.
MATCH p=(:GH_BranchProtectionRule {required_pull_request_reviews: false})-[:GH_ProtectedBy]->(:GH_Branch)
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the branch-protection-no-pr-reviews.json file.

Branch Protection Rules - No Status Checks Required

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.
MATCH p=(:GH_BranchProtectionRule {requires_status_checks: false})-[:GH_ProtectedBy]->(:GH_Branch)
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the branch-protection-no-status-checks.json file.

Branch Protection Rules - Self-Approval Allowed

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.
MATCH p=(:GH_BranchProtectionRule {require_last_push_approval: false})-[:GH_ProtectedBy]->(:GH_Branch)
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the branch-protection-self-approval.json file.

Branch Protection Rules - Stale Reviews Not Dismissed

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.
MATCH p=(:GH_BranchProtectionRule {dismisses_stale_reviews: false})-[:GH_ProtectedBy]->(:GH_Branch)
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the branch-protection-stale-reviews.json file.

Users Who Can Bypass Pull Request Requirements

Finds users and teams that can bypass pull request review requirements on protected branches. These actors can merge code without any reviews.
MATCH p=(actor)-[:GH_BypassPullRequestAllowances]->(rule:GH_BranchProtectionRule)-[:GH_ProtectedBy]->(branch:GH_Branch)
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the bypass-pr-requirements.json file.

Dangerous Branch Permissions

Identifies users with dangerous branch permissions in a GitHub organization, including bypass allowances on protection rules.
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
This query can be imported into BloodHound from the dangerous-branch-perms.json file.

Organizations with default repository permission

Returns organizations that have a default repository permission other than ‘none’.
MATCH (o:GH_Organization)
WHERE o.default_repository_permission <> 'none'
RETURN o
LIMIT 1000
This query can be imported into BloodHound from the default-repository-permissions.json file.

[Demo] SSO Round-Trip: Azure/Okta → GitHub → Cloud Identity

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.
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
This query can be imported into BloodHound from the demo-sso-to-cloud-round-trip.json file.

Dependabot Alerts Disabled for New Repositories

Finds organizations where Dependabot alerts are not enabled for new repositories. Vulnerable dependencies in new repositories will go undetected.
MATCH (org:GH_Organization {dependabot_alerts_enabled_for_new_repositories: false})
RETURN org
LIMIT 1000
This query can be imported into BloodHound from the dependabot-alerts-disabled-new-repos.json file.

Dependabot Security Updates Disabled for New Repositories

Finds organizations where Dependabot security update PRs are not enabled for new repositories. Known vulnerable dependencies will not receive automated fix PRs.
MATCH (org:GH_Organization {dependabot_security_updates_enabled_for_new_repositories: false})
RETURN org
LIMIT 1000
This query can be imported into BloodHound from the dependabot-updates-disabled-new-repos.json file.

Dependency Graph Disabled for New Repositories

Finds organizations where the dependency graph is not enabled for new repositories. Without the dependency graph, transitive dependency vulnerabilities cannot be tracked.
MATCH (org:GH_Organization {dependency_graph_enabled_for_new_repositories: false})
RETURN org
LIMIT 1000
This query can be imported into BloodHound from the dependency-graph-disabled-new-repos.json file.

Environments Where Admins Can Bypass Protections

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.
MATCH p=(:GH_Repository)-[:GH_HasEnvironment]->(env:GH_Environment {can_admins_bypass: true})
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the environments-admin-bypass.json file.

Expired Personal Access Tokens

Finds expired personal access tokens that still exist. Expired tokens should be cleaned up to reduce credential inventory and audit noise.
MATCH p=(:GH_User)-[:GH_HasPersonalAccessToken]->(token:GH_PersonalAccessToken {token_expired: true})
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the expired-pats.json file.

External Identities Without SCIM Provisioning

Finds external identities that lack SCIM synchronization. Without SCIM, user deprovisioning in the identity provider will not automatically revoke GitHub access.
MATCH (ei:GH_ExternalIdentity)
WHERE ei.scim_identity_username = ''
RETURN ei
LIMIT 1000
This query can be imported into BloodHound from the external-identities-without-scim.json file.

GitHub-to-Azure Identity Assumptions

Finds GitHub entities (repositories, branches, environments) that can assume Azure identities via OIDC federation. Verify that each trust relationship is intentional and scoped appropriately.
MATCH p=(src)-[:GH_CanAssumeIdentity]->(cred:AZFederatedIdentityCredential)
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the github-to-azure-identity.json file.

Global Repo Permissions

Returns all users who hold a global repository permission role (i.e., roles that are not default).
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
This query can be imported into BloodHound from the global-repo-perms.json file.

External Identities

Returns all external identities (e.g., Azure or Okta users) that are associated with GitHub users.
MATCH p=(s)-[]->(d:GH_User)
WHERE s:AZUser
OR s:Okta_User
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the hybrid-identities.json file.

Members Can Change Repository Visibility

Finds organizations where members can change repository visibility. This allows any member to make a private repository public, potentially exposing source code and secrets.
MATCH (org:GH_Organization {members_can_change_repo_visibility: true})
RETURN org
LIMIT 1000
This query can be imported into BloodHound from the members-can-change-repo-visibility.json file.

Members Can Create GitHub Pages

Finds organizations where members can create GitHub Pages sites. Pages can be used to host phishing content, data exfiltration endpoints, or other malicious resources.
MATCH (org:GH_Organization {members_can_create_pages: true})
RETURN org
LIMIT 1000
This query can be imported into BloodHound from the members-can-create-pages.json file.

Members Can Create Public Repositories

Finds organizations where members can create internet-facing public repositories. This increases the risk of accidental exposure of proprietary code or secrets.
MATCH (org:GH_Organization {members_can_create_public_repositories: true})
RETURN org
LIMIT 1000
This query can be imported into BloodHound from the members-can-create-public-repos.json file.

Members Can Delete Repositories

Finds organizations where members can delete repositories. This poses a risk of accidental or malicious destruction of code and audit history.
MATCH (org:GH_Organization {members_can_delete_repositories: true})
RETURN org
LIMIT 1000
This query can be imported into BloodHound from the members-can-delete-repos.json file.

Members Can Fork Private Repositories

Finds organizations where members can fork private repositories to personal accounts. Forked copies leave organizational control and oversight.
MATCH (org:GH_Organization {members_can_fork_private_repositories: true})
RETURN org
LIMIT 1000
This query can be imported into BloodHound from the members-can-fork-private-repos.json file.

Members Can Invite Outside Collaborators

Finds organizations where any member can invite external users. This can lead to unauthorized third-party access to repositories without centralized oversight.
MATCH (org:GH_Organization {members_can_invite_outside_collaborators: true})
RETURN org
LIMIT 1000
This query can be imported into BloodHound from the members-can-invite-outside-collaborators.json file.

Organization Owners

Returns all users hold the organization owners role.
MATCH p=(:GH_User)-[:GH_HasRole]->(:GH_OrgRole {short_name:'owners'})
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the org-owners.json file.

Organizations without 2FA

Returns organizations that do not require two-factor authentication.
MATCH (o:GH_Organization)
WHERE o.two_factor_requirement_enabled = false
RETURN o
LIMIT 1000
This query can be imported into BloodHound from the orgs-without-2fa.json file.

PATs with Access to All Repositories

Finds fine-grained personal access tokens scoped to all repositories. A single compromised token grants access to every repository in the organization.
MATCH p=(:GH_User)-[:GH_HasPersonalAccessToken]->(token:GH_PersonalAccessToken {repository_selection: 'all'})
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the pats-all-repo-access.json file.

Pending PAT Requests

Finds pending fine-grained personal access token requests awaiting approval. Review these to ensure requested permissions are appropriate before granting access.
MATCH p=(:GH_User)-[:GH_HasPersonalAccessTokenRequest]->(req:GH_PersonalAccessTokenRequest)
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the pending-pat-requests.json file.

Private Repositories with Forking Allowed

Finds private repositories that allow forking. Forked copies of private repositories can leave organizational governance and visibility.
MATCH (repo:GH_Repository {visibility: 'private', allow_forking: true})
RETURN repo
LIMIT 1000
This query can be imported into BloodHound from the private-repos-forking-allowed.json file.

Privileged Custom Org Roles

Returns all custom organization roles that are privileged (i.e., have permissions that are not default)
MATCH p=(role:GH_OrgRole {type:'custom'})-[r]->(dest)
WHERE dest:GH_Organization
OR dest:GH_OrgRole
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the privileged-custom-org-roles.json file.

Privileged Hybrid Identities

Returns all hybrid identities (e.g., Azure or Okta users) that are associated with GitHub users who hold the organization owners role.
MATCH p=()-[:GH_SyncedTo]->(:GH_User)-[:GH_HasRole]->(:GH_OrgRole {short_name:'owners'})
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the privileged-hybrid-identities.json file.

Public Repositories

Returns all public repositories.
MATCH (repo:GH_Repository {private: false})
RETURN repo
LIMIT 1000
This query can be imported into BloodHound from the public-repos.json file.

Secret Scanning Push Protection Disabled for New Repositories

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.
MATCH (org:GH_Organization {secret_scanning_push_protection_enabled_for_new_repositories: false})
RETURN org
LIMIT 1000
This query can be imported into BloodHound from the push-protection-disabled-new-repos.json file.

Users Who Can Push to Protected Branches

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.
MATCH p=(actor)-[:GH_RestrictionsCanPush]->(rule:GH_BranchProtectionRule)-[:GH_ProtectedBy]->(branch:GH_Branch)
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the push-to-protected-branches.json file.

Repositories with Secret Scanning Disabled

Finds repositories where secret scanning is disabled. Committed credentials in these repositories will not be detected by GitHub.
MATCH (repo:GH_Repository {secret_scanning: 'disabled'})
RETURN repo
LIMIT 1000
This query can be imported into BloodHound from the repos-secret-scanning-disabled.json file.

Repos Vulnerable to Workflow Secret Exfiltration

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.
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
This query can be imported into BloodHound from the repos-vulnerable-to-workflow-secret-exfil.json file.

Repository Workflows

Returns all repository workflows
MATCH p=(:GH_Repository)-[:GH_HasWorkflow]->(:GH_Workflow)
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the repository-workflows.json file.

SAML Configuration Mapping

Finds SAML Identity Providers, their external identities, and mapped users.
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
This query can be imported into BloodHound from the saml-configuration.json file.

Secret Scanning Alerts

Returns all repositories that have secret scanning alerts.
MATCH p=(repo:GH_Repository)-[:GH_Contains]->(:GH_SecretScanningAlert {state:'open'})
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the secret-scanning-alerts.json file.

Secret Scanning Disabled for New Repositories

Finds organizations where secret scanning is not automatically enabled for new repositories. New repositories will not detect committed credentials until manually enabled.
MATCH (org:GH_Organization {secret_scanning_enabled_for_new_repositories: false})
RETURN org
LIMIT 1000
This query can be imported into BloodHound from the secret-scanning-disabled-new-repos.json file.

Secrets Reachable by User

Returns all repo and org secrets reachable by users through write access. Users with write access can create GitHub Actions workflows to access secrets.
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
This query can be imported into BloodHound from the secrets-reachable-by-user.json file.

Team Membership Admins

Returns all users who hold the maintainer role over a team, this also represents team nesting.
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
This query can be imported into BloodHound from the team-membership-admin.json file.

Team Structure

Returns the structure of teams within organizations, including team roles and their members.
MATCH p=(:GH_User)-[:GH_HasRole]->(:GH_TeamRole)-[:GH_MemberOf*1..]->(:GH_Team)
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the team-structure.json file.

Unprotected Branches

Returns all unprotected branches in repositories.
MATCH p=(repo:GH_Repository)-[:GH_HasBranch]-(:GH_Branch {protected: false})
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the unprotected-branches.json file.

Repositories with Workflows and Unprotected Default Branch

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.
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
This query can be imported into BloodHound from the unprotected-default-branch-with-workflow.json file.

Unprotected Default Branches

Returns all default branches in repositories that are not protected.
MATCH p=(repo:GH_Repository)-[:GH_HasBranch]-(branch:GH_Branch {protected: false})
WHERE repo.default_branch = branch.short_name
RETURN p
LIMIT 1000
This query can be imported into BloodHound from the unprotected-default-branches.json file.

Web Commit Signoff Not Required

Finds organizations that do not require sign-off for web-based commits. Without signoff, commit attribution cannot be verified.
MATCH (org:GH_Organization {web_commit_signoff_required: false})
RETURN org
LIMIT 1000
This query can be imported into BloodHound from the web-commit-signoff-not-required.json file.