

GitHound est un collecteur OpenGraph pour GitHub, conçu pour cartographier la structure et les permissions de votre organisation sous forme de graphe de chemins d'attaque navigable. Il permet de :
Modéliser les entités GitHub clés
Visualiser et analyser dans BloodHound
Avec GitHound, vous obtenez un graphe clair et interactif de votre paysage de permissions GitHub, idéal pour les revues de sécurité, les audits de conformité et les investigations rapides d'incidents.
Pour une documentation détaillée, consultez 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
Si la collecte est interrompue, reprenez là où vous vous étiez arrêté :
Invoke-GitHound -Session $session -Resume
GitHound prend en charge à la fois les sessions à jeton d'accès personnel et les sessions d'installation d'application GitHub. Le flux de travail existant de l'application GitHub à portée d'organisation est inchangé :
. ./githound.ps1
$session = New-GitHubJwtSession `
-OrganizationName "YourOrgName" `
-ClientId $clientId `
-PrivateKeyPath $privateKeyPath `
-InstallationId $installationId
Invoke-GitHound -Session $session -CollectAll
La même fonction peut également créer des sessions compatibles entreprise :
. ./githound.ps1
$session = New-GitHubJwtSession `
-EnterpriseName "YourEnterpriseSlug" `
-ClientId $clientId `
-PrivateKeyPath $privateKeyPath `
-InstallationId $installationId `
-PersonalAccessToken $pat
Les sessions compatibles entreprise conservent plusieurs contextes d'authentification sur le GitHound.Session retourné :
Headers : les en-têtes de jeton d'installation de l'application GitHub utilisés pour la collecte normaleJwtHeaders : les en-têtes JWT de l'application GitHub utilisés pour les points de terminaison au niveau de l'application, comme l'énumération des installationsPatHeaders : en-têtes optionnels de jeton d'accès personnel pour les chemins de collecte nécessitant une authentification par jeton utilisateurPour énumérer les installations appartenant à l'application GitHub authentifiée :
Get-GitHubAppInstallation -Session $session |
Select-Object TargetType, InstallationId, Login, Name, SuspendedAt
L'analyse des workflows est désormais intégrée à Invoke-GitHound lorsque vous utilisez -CollectAll. Le collecteur va :
GH_Workflow et les contenus des workflowsGH_WorkflowJob et GH_WorkflowStepGH_CanPwnRequest et GH_CanDispatchTogithound_<orgId>.jsonPour les besoins de reprise/débogage, le point de contrôle intermédiaire de l'analyse des workflows est écrit sous la forme githound_WorkflowAnalysis_<orgId>.json.
GitHound inclut désormais une base minimale de collecte entreprise via Git-HoundEnterprise.
Ce collecteur crée actuellement :
GH_EnterpriseGH_Organization pour les organisations membresGH_Contains de l'entreprise vers ses organisationsLa collecte des utilisateurs d'entreprise via Git-HoundEnterpriseUser ajoute :
GH_UserGH_HasMember de l'entreprise vers ces utilisateursLa collecte SAML d'entreprise via Git-HoundEnterpriseSamlProvider ajoute :
GH_SamlIdentityProviderGH_ExternalIdentityGH_HasSamlIdentityProvider de l'entreprise vers le fournisseurCe chemin nécessite une session adossée à un PAT car GitHub expose le SAML d'entreprise via enterprise.ownerInfo.
La collecte des équipes d'entreprise via Git-HoundEnterpriseTeam ajoute :
GH_EnterpriseTeamGH_AssignedTo des équipes d'entreprise vers les organisations assignéesGH_MemberOf des équipes d'entreprise vers les nœuds GH_Team visibles par l'organisation, de type ent:, via la correspondance de propriétésmembers des équipes d'entreprise et les arêtes GH_HasRole des utilisateurs vers ces rôlesLa collecte des rôles d'entreprise via Git-HoundEnterpriseRole ajoute :
GH_EnterpriseRoleGH_Contains de l'entreprise vers ces rôlesGH_HasRole depuis les utilisateurs et équipes d'entreprise directement assignésowners par défaut, alimenté à partir de enterprise.ownerInfo.admins lorsque les données d'administration d'entreprise adossées à un PAT sont disponiblesPour l'instant, les chaînes brutes de permissions d'entreprise sont conservées sur le nœud GH_EnterpriseRole dans sa propriété permissions, plutôt que d'être développées en arêtes de permissions dédiées.
La collecte SCIM d'entreprise ajoute actuellement :
SCIM_UserSCIM_GroupSCIM_Provisioned de SCIM_User vers GH_ExternalIdentitySCIM_Provisioned de SCIM_Group vers GH_EnterpriseTeam lorsque GitHub expose le group_id de l'équipe d'entrepriseSCIM_MemberOf de SCIM_User vers SCIM_GroupCela donne à GitHound un pont agnostique au fournisseur entre le schéma SCIM partagé et le modèle natif d'identité et d'équipe de GitHub.
Lorsqu'un GH_SamlIdentityProvider collecté identifie le fournisseur d'identité en amont, GitHound peut également ajouter des arêtes de corrélation SCIM tenant compte du fournisseur dans la sortie 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_environmentidGitHound conserve la couche SCIM dans sa propre sortie sidecar afin que ces correspondances restent visibles sans mélanger les nœuds natifs SCIM dans le graphe principal natif GitHub de l'entreprise :
githound_<entId>.json contient les données natives GitHub de l'entreprisegithound_scim_<entId>.json contient les nœuds natifs SCIM et les arêtes de pont SCIMgithound_saml_<entId>.json contient les données SAML et d'identité externegithound_hybrid_<entId>.json contient les arêtes inter-modèles telles que SAML_Implements, SAML_HasAccount et GH_SyncedTogithound_saml_<entId>.json contient également la topologie SAML normalisée pour le fournisseur de services GitHub, y compris SAML_TrustsIssuer et SAML_HasAssertionConsumerServiceLe modèle natif de fournisseur d'identité GitHub reste intact dans les sorties natives GitHub/SAML :
GH_ExternalIdentityGH_HasExternalIdentityGH_MapsToUserLa couche SAML normalisée dans githound_hybrid_<entId>.json place désormais SAML_HasAccount directement sur GH_User, tout en dérivant match_values des propriétés orientées SAML du GH_ExternalIdentity lié, telles que saml_identity_name_id et saml_identity_username.
Les nœuds d'organisation GH_Organization émis par la collecte entreprise sont intentionnellement marqués collected = false. Ils représentent une découverte structurelle à partir du contexte entreprise et sont destinés à être enrichis ultérieurement par la collecte d'organisation normale.
Pour une orchestration axée entreprise d'abord, Invoke-GitHoundEnterprise collecte les données prises en charge au niveau de l'entreprise, énumère les installations d'organisations associées, puis exécute le flux de travail existant Invoke-GitHound pour chaque organisation dans son propre sous-répertoire sous le chemin de point de contrôle choisi.
Exemple :
$session = New-GitHubJwtSession `
-EnterpriseName "your-enterprise-slug" `
-ClientId $clientId `
-PrivateKeyPath $privateKeyPath `
-InstallationId $enterpriseInstallationId `
-PersonalAccessToken $pat
Invoke-GitHoundEnterprise -Session $session -CheckpointPath "./output/your-enterprise" -CollectAll
Pour un test uniquement entreprise sans énumérer les organisations associées :
Invoke-GitHoundEnterprise -Session $session -CheckpointPath "./output/your-enterprise" -EnterpriseOnly

Pour une documentation détaillée, consultez BloodHound Docs - GitHound Schema.
Catégories d'arêtes clés :
Modèle de chemin d'attaque principal :
(:GH_User)-[:GH_HasRole|GH_MemberOf|GH_AddMember*1..]->(:GH_RepoRole)-[:GH_AdminTo|GH_CanPush]->(:GH_Repository)
Trouvez l'identifiant d'objet de votre utilisateur cible :
MATCH (n:GH_User)
RETURN n
ASTUCE : Sélectionnez la disposition en tableau
https://github.com/user-attachments/assets/1ddfd075-2a15-4aa9-bad7-74c43e6c82d6
Remplacez la valeur <object_id> dans la requête suivante par l'identifiant d'objet de l'utilisateur :
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

Obtenez l'identifiant d'objet de votre dépôt cible :
MATCH (n:GH_Repository)
RETURN n
Prenez l'identifiant d'objet de votre dépôt cible et remplacez la valeur <object_id> dans la requête suivante par celui-ci :
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

Recherchez les entités GitHub pouvant assumer des identités fédérées Azure (relations de confiance 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
Nous accueillons et apprécions vos contributions ! Pour rendre le processus fluide et efficace, veuillez suivre ces étapes :
Discutez de votre idée
Fork & créez une branche
Forkez ce dépôt sur votre propre compte.
Créez une branche thématique pour votre travail :
git checkout -b feat/my-new-feature
Implémentez et testez
Suivez le style et les modèles existants du dépôt.
Ajoutez ou mettez à jour les tests/exemples pour couvrir vos modifications.
Vérifiez que votre code s'exécute comme prévu :
# e.g. dot-source the collector and run it, or load the model.json in BloodHound
Soumettez une pull request
Poussez votre branche vers votre fork :
git push origin feat/my-new-feature
Ouvrez une pull request contre la branche main de ce dépôt.
Dans la description de votre PR, veuillez inclure :
Revue et fusion
Merci d'aider à améliorer cette extension ! 🎉
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.
Sauf mention contraire par un fichier LICENSE de niveau inférieur ou un en-tête de licence, tous les fichiers de ce dépôt sont publiés sous la licence Apache-2.0. Une copie complète de la licence se trouve dans le fichier LICENSE au niveau racine.
| Catégorie | Arêtes clés | Description |
|---|
| Contenance | GH_Contains, GH_Owns | Hiérarchie organisationnelle |
| Attribution de rôles | GH_HasRole, GH_MemberOf, GH_HasBaseRole | Qui a quels rôles |
| Permissions de dépôt | GH_AdminTo, GH_CanPush, GH_CanPull | Ce que les rôles peuvent faire |
| Protections de branche | GH_BypassPullRequestAllowances, GH_RestrictionsCanPush | Accès au niveau des branches |
| Secrets | GH_HasSecret | Cartographie des accès aux secrets |
| Multi-cloud | GH_CanAssumeIdentity, GH_SyncedTo | Chemins d'attaque vers Azure/AWS |