

GitHound é um coletor OpenGraph do BloodHound para GitHub, projetado para mapear a estrutura e as permissões da sua organização em um grafo navegável de caminhos de ataque. Ele:
Modela as Principais Entidades do GitHub
Visualize e Analise no BloodHound
Com o GitHound, você obtém um grafo claro e interativo do panorama de permissões do GitHub — perfeito para revisões de segurança, auditorias de conformidade e investigações rápidas de incidentes.
Para documentação detalhada, consulte BloodHound Docs - GitHound.
# 1. Load the collector
. ./githound.ps1
# 2. Create a session with your Personal Access Token
$session = New-GitHubSession -OrganizationName "YourOrgName" -Token (Get-Clipboard)
# 3. Run the collection
Invoke-GitHound -Session $session
# 4. Upload the resulting githound_<orgId>.json file to BloodHound
Se a coleta for interrompida, retome de onde parou:
Invoke-GitHound -Session $session -Resume
O GitHound suporta tanto sessões de Personal Access Token quanto sessões de instalação do GitHub App. O fluxo de trabalho existente do GitHub App com escopo de organização permanece inalterado:
. ./githound.ps1
$session = New-GitHubJwtSession `
-OrganizationName "YourOrgName" `
-ClientId $clientId `
-PrivateKeyPath $privateKeyPath `
-InstallationId $installationId
Invoke-GitHound -Session $session -CollectAll
A mesma função também pode criar sessões com capacidade enterprise:
. ./githound.ps1
$session = New-GitHubJwtSession `
-EnterpriseName "YourEnterpriseSlug" `
-ClientId $clientId `
-PrivateKeyPath $privateKeyPath `
-InstallationId $installationId `
-PersonalAccessToken $pat
Sessões com capacidade enterprise mantêm múltiplos contextos de autenticação no GitHound.Session retornado:
Headers: os cabeçalhos do token de instalação do GitHub App usados para a coleta normalJwtHeaders: cabeçalhos JWT do GitHub App usados para endpoints de nível de aplicativo, como a enumeração de instalaçõesPatHeaders: cabeçalhos opcionais de Personal Access Token para caminhos de coleta que exigem autenticação por token de usuárioPara enumerar as instalações que pertencem ao GitHub App autenticado:
Get-GitHubAppInstallation -Session $session |
Select-Object TargetType, InstallationId, Login, Name, SuspendedAt
O parsing de workflow agora está integrado ao Invoke-GitHound quando você usa -CollectAll. O coletor
irá:
GH_Workflow e conteúdos de workflowGH_WorkflowJob e GH_WorkflowStepGH_CanPwnRequest e GH_CanDispatchTogithound_<orgId>.jsonPara fins de retomada/depuração, o checkpoint intermediário da análise de workflow é gravado como
githound_WorkflowAnalysis_<orgId>.json.
O GitHound agora inclui uma base mínima de coleta enterprise por meio do Git-HoundEnterprise.
Esse coletor atualmente cria:
GH_EnterpriseGH_Organization para organizações membroGH_Contains da enterprise para suas organizaçõesA coleta de usuários enterprise por meio do Git-HoundEnterpriseUser adiciona:
GH_UserGH_HasMember da enterprise para esses usuáriosA coleta SAML enterprise por meio do Git-HoundEnterpriseSamlProvider adiciona:
GH_SamlIdentityProviderGH_ExternalIdentityGH_HasSamlIdentityProvider da enterprise para o provedorEsse caminho exige uma sessão baseada em PAT porque o GitHub expõe o SAML enterprise por meio de
enterprise.ownerInfo.
A coleta de equipes enterprise por meio do Git-HoundEnterpriseTeam adiciona:
GH_EnterpriseTeamGH_AssignedTo de equipes enterprise para organizações designadasGH_MemberOf de equipes enterprise para nós GH_Team ent: visíveis na org usando correspondência de propriedadesmembers de equipe enterprise e arestas GH_HasRole de usuários para essas funçõesA coleta de funções enterprise por meio do Git-HoundEnterpriseRole adiciona:
GH_EnterpriseRoleGH_Contains da enterprise para essas funçõesGH_HasRole de usuários e equipes enterprise designados diretamenteowners preenchida a partir de enterprise.ownerInfo.admins quando dados administrativos enterprise baseados em PAT estão disponíveisPor enquanto, as strings brutas de permissão enterprise são preservadas no nó GH_EnterpriseRole em sua propriedade permissions, em vez de serem expandidas em arestas de permissão dedicadas.
A coleta SCIM enterprise atualmente adiciona:
SCIM_UserSCIM_GroupSCIM_Provisioned de SCIM_User para GH_ExternalIdentitySCIM_Provisioned de SCIM_Group para GH_EnterpriseTeam quando o GitHub expõe o group_id da equipe enterpriseSCIM_MemberOf de SCIM_User para SCIM_GroupIsso dá ao GitHound uma ponte agnóstica de provedor do esquema SCIM compartilhado para o modelo nativo de identidade e equipe enterprise do GitHub.
Quando um GH_SamlIdentityProvider coletado identifica o IdP upstream, o GitHound também pode adicionar arestas de correlação SCIM cientes do provedor dentro da saída sidecar SCIM:
Okta_User -> SCIM_User
Okta_User.id = SCIM_User.externalIdOkta_Group -> SCIM_Group
Okta_Group.name = SCIM_Group.externalIdOkta_Group.oktaDomain = GH_SamlIdentityProvider.foreign_environmentidO GitHound mantém a camada SCIM em sua própria saída sidecar para que esses mapeamentos permaneçam visíveis sem misturar nós nativos SCIM no grafo enterprise principal nativo do GitHub:
githound_<entId>.json contém dados enterprise nativos do GitHubgithound_scim_<entId>.json contém nós nativos SCIM e arestas de ponte SCIMgithound_saml_<entId>.json contém dados de identidade SAML e externagithound_hybrid_<entId>.json contém arestas entre modelos, como SAML_Implements, SAML_HasAccount e GH_SyncedTogithound_saml_<entId>.json também contém a topologia SAML normalizada para o provedor de serviços GitHub, incluindo SAML_TrustsIssuer e SAML_HasAssertionConsumerServiceO modelo nativo de provedor de identidade do GitHub permanece intacto nas saídas nativas GitHub/SAML:
GH_ExternalIdentityGH_HasExternalIdentityGH_MapsToUserA camada SAML normalizada em githound_hybrid_<entId>.json agora coloca SAML_HasAccount diretamente em GH_User, ao mesmo tempo que deriva match_values das propriedades voltadas para SAML do GH_ExternalIdentity vinculado, como saml_identity_name_id e saml_identity_username.
Os stubs GH_Organization emitidos pela coleta enterprise são intencionalmente marcados como
collected = false. Eles representam a descoberta estrutural a partir do contexto enterprise e
devem ser enriquecidos posteriormente pela coleta normal de organizações.
Para orquestração enterprise-first, o Invoke-GitHoundEnterprise coletará os dados
com escopo enterprise suportados, enumerará as instalações de organizações relacionadas e, em seguida, executará o
fluxo de trabalho existente do Invoke-GitHound para cada organização em seu próprio subdiretório sob o
caminho de checkpoint escolhido.
Exemplo:
$session = New-GitHubJwtSession `
-EnterpriseName "your-enterprise-slug" `
-ClientId $clientId `
-PrivateKeyPath $privateKeyPath `
-InstallationId $enterpriseInstallationId `
-PersonalAccessToken $pat
Invoke-GitHoundEnterprise -Session $session -CheckpointPath "./output/your-enterprise" -CollectAll
Para testes apenas enterprise, sem enumerar as organizações relacionadas:
Invoke-GitHoundEnterprise -Session $session -CheckpointPath "./output/your-enterprise" -EnterpriseOnly

Para documentação detalhada, consulte BloodHound Docs - GitHound Schema.
Principais categorias de arestas:
Padrão principal de caminho de ataque:
(:GH_User)-[:GH_HasRole|GH_MemberOf|GH_AddMember*1..]->(:GH_RepoRole)-[:GH_AdminTo|GH_CanPush]->(:GH_Repository)
Encontre o identificador de objeto para o usuário-alvo:
MATCH (n:GH_User)
RETURN n
DICA: Selecione Table Layout
https://github.com/user-attachments/assets/1ddfd075-2a15-4aa9-bad7-74c43e6c82d6
Substitua o valor <object_id> na consulta subsequente pelo identificador de objeto do usuário:
MATCH p = (:GH_User {objectid:"<object_id>"})-[:GH_MemberOf|GH_AddMember|GH_HasRole|GH_HasBaseRole|GH_Owns*1..]->(:GH_RepoRole)-[:GH_WriteRepoContents]->(:GH_Repository)
RETURN p

Obtenha o identificador de objeto para o repositório-alvo:
MATCH (n:GH_Repository)
RETURN n
Pegue o identificador de objeto do repositório-alvo e substitua o valor <object_id> na consulta subsequente por ele:
MATCH p = (:GH_User)-[:GH_MemberOf|GH_HasRole|GH_HasBaseRole|GH_Owns|GH_AddMember*1..]->(:GH_RepoRole)-[:GH_WriteRepoContents]->(:GH_Repository {objectid:"<object_id>"})
RETURN p

MATCH p = (:GH_User)-[:GH_HasRole|GH_HasBaseRole]->(:GH_OrgRole {short_name: "owners"})
RETURN p

MATCH p = (:AZUser)-[:GH_SyncedTo]->(:GH_User)
RETURN p

Encontre entidades do GitHub que podem assumir identidades federadas do Azure (relações de confiança OIDC):
// All GitHub → Azure OIDC attack paths
MATCH p = (:GH_Repository|GH_Branch|GH_Environment)-[:GH_CanAssumeIdentity]->(:AZFederatedIdentityCredential)
RETURN p
// Users with paths to Azure via GitHub Actions
MATCH p = (:GH_User)-[:GH_HasRole|GH_MemberOf|GH_AddMember*1..]->(:GH_RepoRole)-[:GH_CanPush]->(:GH_Repository)-[:GH_CanAssumeIdentity]->(:AZFederatedIdentityCredential)
RETURN p
MATCH p = (:GH_Repository)-[:GH_HasSecret]->(:GH_OrgSecret)
RETURN p
MATCH p = (:GH_Repository)-[:GH_Contains]->(:GH_SecretScanningAlert)
RETURN p
Agradecemos e valorizamos suas contribuições! Para tornar o processo tranquilo e eficiente, siga estas etapas:
Discuta sua Ideia
Faça um Fork e Crie um Branch
Faça um fork deste repositório para sua própria conta.
Crie um branch de tópico para o seu trabalho:
git checkout -b feat/my-new-feature
Implemente e Teste
Siga o estilo e os padrões existentes no repositório.
Adicione ou atualize testes/exemplos para cobrir suas alterações.
Verifique se o seu código executa conforme o esperado:
# e.g. dot-source the collector and run it, or load the model.json in BloodHound
Envie um Pull Request
Faça push do seu branch para o seu fork:
git push origin feat/my-new-feature
Abra um Pull Request contra o branch main deste repositório.
Na descrição do seu PR, inclua:
Revise e Mescle
Obrigado por ajudar a melhorar esta extensão! 🎉
Copyright 2025 Jared Atkinson
Licensed under the Apache License, Version 2.0
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Salvo indicação em contrário por um arquivo LICENSE de nível inferior ou cabeçalho de licença, todos os arquivos deste repositório são disponibilizados sob a licença Apache-2.0. Uma cópia completa da licença pode ser encontrada no arquivo LICENSE no nível raiz.
| Categoria | Arestas-chave | Descrição |
|---|
| Contenção | GH_Contains, GH_Owns | Hierarquia organizacional |
| Atribuição de Funções | GH_HasRole, GH_MemberOf, GH_HasBaseRole | Quem tem quais funções |
| Permissões de Repositório | GH_AdminTo, GH_CanPush, GH_CanPull | O que as funções podem fazer |
| Proteções de Branch | GH_BypassPullRequestAllowances, GH_RestrictionsCanPush | Acesso no nível do branch |
| Segredos | GH_HasSecret | Mapeamento de acesso a segredos |
| Entre Nuvens | GH_CanAssumeIdentity, GH_SyncedTo | Caminhos de ataque para Azure/AWS |